Opentk/Source/OpenTK/Graphics/DisplayDevice.cs

444 lines
15 KiB
C#
Raw Normal View History

2008-01-23 12:44:32 +00:00
#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.
*/
2008-01-23 12:44:32 +00:00
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
2008-01-26 14:02:58 +00:00
using System.Threading;
using System.Windows.Forms;
2008-01-23 12:44:32 +00:00
namespace OpenTK.Graphics
{
/// <summary>
/// Defines a display device on the underlying system, and provides
/// methods to query and change its display parameters.
/// </summary>
2008-01-23 14:39:27 +00:00
public class DisplayDevice
2008-01-23 12:44:32 +00:00
{
// 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!
2008-01-23 12:44:32 +00:00
DisplayResolution current_resolution, original_resolution;
List<DisplayResolution> available_resolutions = new List<DisplayResolution>();
2008-01-23 12:44:32 +00:00
bool primary;
2008-01-23 14:39:27 +00:00
static List<DisplayDevice> available_displays = new List<DisplayDevice>();
2008-01-23 12:44:32 +00:00
static object display_lock = new object();
2008-01-23 14:39:27 +00:00
static DisplayDevice primary_display;
2008-01-26 14:02:58 +00:00
static FadeEffect effect = new FadeEffect();
2008-01-23 12:44:32 +00:00
2008-01-24 21:20:59 +00:00
static IDisplayDeviceDriver implementation;
2008-01-23 12:44:32 +00:00
#region --- Constructors ---
2008-01-23 14:39:27 +00:00
static DisplayDevice()
2008-01-23 12:44:32 +00:00
{
2008-01-24 21:20:59 +00:00
switch (System.Environment.OSVersion.Platform)
{
case PlatformID.Unix:
case (PlatformID)128:
implementation = new OpenTK.Platform.X11.X11XrandrDisplayDevice();
2008-01-24 21:20:59 +00:00
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;
// }
//}
2008-01-23 12:44:32 +00:00
}
internal DisplayDevice(DisplayResolution currentResolution, bool primary,
IEnumerable<DisplayResolution> availableResolutions)
2008-01-23 12:44:32 +00:00
{
this.current_resolution = currentResolution;
2008-01-23 12:44:32 +00:00
this.primary = primary;
this.available_resolutions.AddRange(availableResolutions);
2008-01-25 10:20:25 +00:00
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();
2008-01-25 10:20:25 +00:00
lock (display_lock)
{
available_displays.Add(this);
if (primary)
primary_display = this;
}
2008-01-23 12:44:32 +00:00
}
#endregion
#region --- Public Methods ---
#region public int Width
/// <summary>Gets a System.Int32 that contains the width of this display in pixels.</summary>
public int Width { get { return current_resolution.Width; } }
#endregion
#region public int Height
/// <summary>Gets a System.Int32 that contains the height of this display in pixels.</summary>
public int Height { get { return current_resolution.Height; } }
#endregion
#region public int BitsPerPixel
/// <summary>Gets a System.Int32 that contains number of bits per pixel of this display. Typical values include 8, 16, 24 and 32.</summary>
public int BitsPerPixel { get { return current_resolution.BitsPerPixel; } }
#endregion
#region public float RefreshRate
/// <summary>
/// Gets a System.Single representing the vertical refresh rate of this display.
/// </summary>
public float RefreshRate
{
get { return current_resolution.RefreshRate; }
}
2008-01-23 12:44:32 +00:00
#endregion
#region public bool IsPrimary
2008-01-23 12:44:32 +00:00
/// <summary>Gets a System.Boolean that indicates whether this Display is the primary Display in systems with multiple Displays.</summary>
public bool IsPrimary { get { return primary; } }
2008-01-23 12:44:32 +00:00
#endregion
#region public DisplayResolution SelectResolution(int width, int height, int bitsPerPixel, float refreshRate)
/// <summary>
/// Selects an available resolution that matches the specified parameters.
/// </summary>
/// <param name="width">The width of the requested resolution in pixels.</param>
/// <param name="height">The height of the requested resolution in pixels.</param>
/// <param name="bitsPerPixel">The bits per pixel of the requested resolution.</param>
/// <param name="refreshRate">The refresh rate of the requested resolution in Herz.</param>
/// <returns>The requested DisplayResolution or null if the parameters cannot be met.</returns>
/// <remarks>
/// <para>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).</para>
/// <para>This function generates garbage.</para>
/// </remarks>
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
/// <summary>
/// Gets an array of OpenTK.DisplayResolution objects, which describe all available resolutions
/// for this device.
/// </summary>
public DisplayResolution[] AvailableResolutions
{
get
{
lock (display_lock)
{
return available_resolutions.ToArray();
}
}
}
#endregion
#region public void ChangeResolution(DisplayResolution resolution)
/// <summary>Changes the resolution of the DisplayDevice.</summary>
/// <param name="resolution">The resolution to set. <see cref="DisplayDevice.SelectResolution"/></param>
/// <exception cref="GraphicsModeException">Thrown if the requested resolution could not be set.</exception>
public void ChangeResolution(DisplayResolution resolution)
{
if (resolution == null)
throw new ArgumentNullException("resolution", "Must be a valid resolution.");
if (resolution == current_resolution)
return;
effect.FadeOut();
2008-01-26 14:02:58 +00:00
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));
2008-01-26 14:02:58 +00:00
effect.FadeIn();
}
#endregion
#region public void ChangeResolution(DisplayResolution resolution)
/// <summary>Changes the resolution of the DisplayDevice.</summary>
/// <param name="width">The new width of the DisplayDevice.</param>
/// <param name="height">The new height of the DisplayDevice.</param>
/// <param name="bitsPerPixel">The new bits per pixel of the DisplayDevice.</param>
/// <param name="refreshRate">The new refresh rate of the DisplayDevice.</param>
/// <exception cref="GraphicsModeException">Thrown if the requested resolution could not be set.</exception>
public void ChangeResolution(int width, int height, int bitsPerPixel, float refreshRate)
{
this.ChangeResolution(this.SelectResolution(width, height, bitsPerPixel, refreshRate));
}
#endregion
#region public void RestoreResolution()
/// <summary>Restores the original resolution of the DisplayDevice.</summary>
/// <exception cref="GraphicsModeException">Thrown if the original resolution could not be restored.</exception>
public void RestoreResolution()
{
if (original_resolution != null)
2008-01-26 14:02:58 +00:00
{
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));
2008-01-26 14:02:58 +00:00
effect.FadeIn();
}
}
#endregion
#region public static DisplayDevice[] AvailableDisplays
2008-01-23 12:44:32 +00:00
/// <summary>
/// Gets an array of OpenTK.DisplayDevice objects, which describe all available display devices.
2008-01-23 12:44:32 +00:00
/// </summary>
2008-01-23 14:39:27 +00:00
public static DisplayDevice[] AvailableDisplays
2008-01-23 12:44:32 +00:00
{
get
{
lock (display_lock)
{
return available_displays.ToArray();
}
}
}
#endregion
#region public static DisplayDevice Default
/// <summary>Gets the default (primary) display of this system.</summary>
public static DisplayDevice Default { get { return primary_display; } }
2008-01-23 12:44:32 +00:00
#endregion
#endregion
#region --- Overrides ---
#region public override string ToString()
2008-01-23 12:44:32 +00:00
/// <summary>
/// Returns a System.String representing this DisplayDevice.
/// </summary>
/// <returns>A System.String representing this DisplayDevice.</returns>
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)
/// <summary>Determines whether the specified DisplayDevices are equal.</summary>
/// <param name="obj">The System.Object to check against.</param>
/// <returns>True if the System.Object is an equal DisplayDevice; false otherwise.</returns>
//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()
/// <summary>Returns a unique hash representing this DisplayDevice.</summary>
/// <returns>A System.Int32 that may serve as a hash code for this DisplayDevice.</returns>
//public override int GetHashCode()
//{
// return current_resolution.GetHashCode() ^ IsPrimary.GetHashCode() ^ available_resolutions.Count;
//}
#endregion
#endregion
2008-01-23 12:44:32 +00:00
}
2008-01-26 14:02:58 +00:00
#region --- FadeEffect ---
class FadeEffect : IDisposable
{
List<Form> forms = new List<Form>();
double opacity_step = 0.04;
2008-01-26 14:02:58 +00:00
int sleep_step;
internal FadeEffect()
{
foreach (Screen s in Screen.AllScreens)
{
Form form = new Form();
form.ShowInTaskbar = false;
form.StartPosition = FormStartPosition.Manual;
2008-01-26 14:02:58 +00:00
form.WindowState = FormWindowState.Maximized;
form.FormBorderStyle = FormBorderStyle.None;
2008-01-26 14:02:58 +00:00
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);
//forms[count].Size = new System.Drawing.Size(4096, 4096);
count++;
}
2008-01-26 14:02:58 +00:00
}
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)
{
2008-01-26 14:02:58 +00:00
form.Opacity += opacity_step;
2008-01-27 15:53:04 +00:00
form.Refresh();
}
2008-01-26 14:02:58 +00:00
Thread.Sleep(sleep_step);
}
}
internal void FadeIn()
{
MoveToStartPositions();
foreach (Form form in forms)
form.Opacity = 1.0;
while (!FadedIn)
{
foreach (Form form in forms)
{
2008-01-26 14:02:58 +00:00
form.Opacity -= opacity_step;
2008-01-27 15:53:04 +00:00
form.Refresh();
}
2008-01-26 14:02:58 +00:00
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
2008-01-23 12:44:32 +00:00
}