#region --- License --- /* Licensed under the MIT/X11 license. * Copyright (c) 2006-2008 the OpenTK team. * This notice may not be removed. * See license.txt for licensing detailed licensing details. */ #endregion using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Threading; using System.Windows.Forms; namespace OpenTK.Graphics { /// /// Defines a display device on the underlying system, and provides /// methods to query and change its display parameters. /// public class DisplayDevice { // TODO: Add support for refresh rate queries and switches. // TODO: Check whether bits_per_pixel works correctly under Mono/X11. // TODO: Add properties that describe the 'usable' size of the Display, i.e. the maximized size without the taskbar etc. // TODO: Does not detect changes to primary device. // TODO: Mono does not support System.Windows.Forms.Screen.BitsPerPixel -- find workaround! DisplayResolution current_resolution, original_resolution; List available_resolutions = new List(); bool primary; static List available_displays = new List(); static object display_lock = new object(); static DisplayDevice primary_display; static FadeEffect effect = new FadeEffect(); static IDisplayDeviceDriver implementation; #region --- Constructors --- static DisplayDevice() { switch (System.Environment.OSVersion.Platform) { case PlatformID.Unix: case (PlatformID)128: implementation = new OpenTK.Platform.X11.X11XrandrDisplayDevice(); break; default: implementation = new OpenTK.Platform.Windows.WinDisplayDeviceDriver(); break; } //lock (display_lock) //{ // int i = 0; // foreach (System.Windows.Forms.Screen scr in System.Windows.Forms.Screen.AllScreens) // { // available_displays.Add(new DisplayDevice(scr.Bounds.Width, scr.Bounds.Height, 32, 0, scr.Primary)); // if (scr.Primary) // primary_display = available_displays[i]; // ++i; // } //} } internal DisplayDevice(DisplayResolution currentResolution, bool primary, IEnumerable availableResolutions) { this.current_resolution = currentResolution; this.primary = primary; this.available_resolutions.AddRange(availableResolutions); Debug.Print("DisplayDevice {0} ({1}) supports {2} resolutions.", available_displays.Count, primary ? "primary" : "secondary", available_resolutions.Count); Debug.Indent(); foreach (DisplayResolution res in available_resolutions) Debug.Print(res == current_resolution ? String.Format(">> {0} <<", res.ToString()) : res.ToString()); Debug.Unindent(); lock (display_lock) { available_displays.Add(this); if (primary) primary_display = this; } } #endregion #region --- Public Methods --- #region public int Width /// Gets a System.Int32 that contains the width of this display in pixels. public int Width { get { return current_resolution.Width; } } #endregion #region public int Height /// Gets a System.Int32 that contains the height of this display in pixels. public int Height { get { return current_resolution.Height; } } #endregion #region public int BitsPerPixel /// Gets a System.Int32 that contains number of bits per pixel of this display. Typical values include 8, 16, 24 and 32. public int BitsPerPixel { get { return current_resolution.BitsPerPixel; } } #endregion #region public float RefreshRate /// /// Gets a System.Single representing the vertical refresh rate of this display. /// public float RefreshRate { get { return current_resolution.RefreshRate; } } #endregion #region public bool IsPrimary /// Gets a System.Boolean that indicates whether this Display is the primary Display in systems with multiple Displays. public bool IsPrimary { get { return primary; } } #endregion #region public DisplayResolution SelectResolution(int width, int height, int bitsPerPixel, float refreshRate) /// /// Selects an available resolution that matches the specified parameters. /// /// The width of the requested resolution in pixels. /// The height of the requested resolution in pixels. /// The bits per pixel of the requested resolution. /// The refresh rate of the requested resolution in Herz. /// The requested DisplayResolution or null if the parameters cannot be met. /// /// A parameter set to 0 will not be used in the search (e.g. if refreshRate is 0, any refresh rate will be considered valid). /// This function generates garbage. /// public DisplayResolution SelectResolution(int width, int height, int bitsPerPixel, float refreshRate) { return available_resolutions.Find(delegate(DisplayResolution test) { return ((width > 0 && width == test.Width) || width == 0) && ((height > 0 && height == test.Height) || height == 0) && ((bitsPerPixel > 0 && bitsPerPixel == test.BitsPerPixel) || bitsPerPixel == 0) && ((refreshRate > 0 && System.Math.Abs(refreshRate - test.RefreshRate) < 1.0) || refreshRate == 0); }); } #endregion #region public DisplayResolution[] AvailableResolutions /// /// Gets an array of OpenTK.DisplayResolution objects, which describe all available resolutions /// for this device. /// public DisplayResolution[] AvailableResolutions { get { lock (display_lock) { return available_resolutions.ToArray(); } } } #endregion #region public void ChangeResolution(DisplayResolution resolution) /// Changes the resolution of the DisplayDevice. /// The resolution to set. /// Thrown if the requested resolution could not be set. public void ChangeResolution(DisplayResolution resolution) { if (resolution == null) throw new ArgumentNullException("resolution", "Must be a valid resolution."); if (resolution == current_resolution) return; effect.FadeOut(); if (implementation.TryChangeResolution(this, resolution)) { if (original_resolution == null) original_resolution = current_resolution; current_resolution = resolution; } else throw new GraphicsModeException(String.Format("Device {0}: Failed to change resolution to {1}.", this, resolution)); effect.FadeIn(); } #endregion #region public void ChangeResolution(DisplayResolution resolution) /// Changes the resolution of the DisplayDevice. /// The new width of the DisplayDevice. /// The new height of the DisplayDevice. /// The new bits per pixel of the DisplayDevice. /// The new refresh rate of the DisplayDevice. /// Thrown if the requested resolution could not be set. public void ChangeResolution(int width, int height, int bitsPerPixel, float refreshRate) { this.ChangeResolution(this.SelectResolution(width, height, bitsPerPixel, refreshRate)); } #endregion #region public void RestoreResolution() /// Restores the original resolution of the DisplayDevice. /// Thrown if the original resolution could not be restored. public void RestoreResolution() { if (original_resolution != null) { effect.FadeOut(); if (implementation.TryRestoreResolution(this)) { current_resolution = original_resolution; original_resolution = null; } else throw new GraphicsModeException(String.Format("Device {0}: Failed to restore resolution.", this)); effect.FadeIn(); } } #endregion #region public static DisplayDevice[] AvailableDisplays /// /// Gets an array of OpenTK.DisplayDevice objects, which describe all available display devices. /// public static DisplayDevice[] AvailableDisplays { get { lock (display_lock) { return available_displays.ToArray(); } } } #endregion #region public static DisplayDevice Default /// Gets the default (primary) display of this system. public static DisplayDevice Default { get { return primary_display; } } #endregion #endregion #region --- Overrides --- #region public override string ToString() /// /// Returns a System.String representing this DisplayDevice. /// /// A System.String representing this DisplayDevice. public override string ToString() { return String.Format("{0}: {1} ({2} modes available)", IsPrimary ? "Primary" : "Secondary", current_resolution.ToString(), available_resolutions.Count); } #endregion #region public override bool Equals(object obj) /// Determines whether the specified DisplayDevices are equal. /// The System.Object to check against. /// True if the System.Object is an equal DisplayDevice; false otherwise. //public override bool Equals(object obj) //{ // if (obj is DisplayDevice) // { // DisplayDevice dev = (DisplayDevice)obj; // return // IsPrimary == dev.IsPrimary && // current_resolution == dev.current_resolution && // available_resolutions.Count == dev.available_resolutions.Count; // } // return false; //} #endregion #region public override int GetHashCode() /// Returns a unique hash representing this DisplayDevice. /// A System.Int32 that may serve as a hash code for this DisplayDevice. //public override int GetHashCode() //{ // return current_resolution.GetHashCode() ^ IsPrimary.GetHashCode() ^ available_resolutions.Count; //} #endregion #endregion } #region --- FadeEffect --- class FadeEffect : IDisposable { List
forms = new List(); double opacity_step = 0.04; int sleep_step; internal FadeEffect() { foreach (Screen s in Screen.AllScreens) { Form form = new Form(); form.ShowInTaskbar = false; form.StartPosition = FormStartPosition.Manual; form.FormBorderStyle = FormBorderStyle.None; form.WindowState = FormWindowState.Maximized; form.TopMost = true; form.BackColor = System.Drawing.Color.Black; forms.Add(form); } sleep_step = 10 / forms.Count; MoveToStartPositions(); } void MoveToStartPositions() { //int count = 0; //foreach (Screen s in Screen.AllScreens) // forms[count++].Location = new System.Drawing.Point(s.Bounds.X, s.Bounds.Y); } bool FadedOut { get { bool ready = true; foreach (Form form in forms) ready = ready && form.Opacity >= 1.0; return ready; } } bool FadedIn { get { bool ready = true; foreach (Form form in forms) ready = ready && form.Opacity <= 0.0; return ready; } } internal void FadeOut() { MoveToStartPositions(); foreach (Form form in forms) { form.Opacity = 0.0; form.Visible = true; } while (!FadedOut) { foreach (Form form in forms) { form.Opacity += opacity_step; form.Refresh(); } Thread.Sleep(sleep_step); } } internal void FadeIn() { MoveToStartPositions(); foreach (Form form in forms) form.Opacity = 1.0; while (!FadedIn) { foreach (Form form in forms) { form.Opacity -= opacity_step; form.Refresh(); } Thread.Sleep(sleep_step); } foreach (Form form in forms) form.Visible = false; } #region IDisposable Members public void Dispose() { foreach (Form form in forms) form.Dispose(); } #endregion } #endregion }