#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#endregion
using System;
using System.ComponentModel;
using System.Drawing;
using OpenTK.Graphics;
using OpenTK.Input;
using OpenTK.Platform;
namespace OpenTK {
/// Instances of this class implement the interface on the current platform.
public class NativeWindow : INativeWindow {
private readonly GameWindowFlags options;
private readonly DisplayDevice device;
private readonly INativeWindow implementation;
private bool disposed, events;
/// Constructs a new NativeWindow with default attributes without enabling events.
public NativeWindow()
: this(640, 480, "OpenTK Native Window", GameWindowFlags.Default, GraphicsMode.Default, DisplayDevice.Default) { }
/// Constructs a new centered NativeWindow with the specified attributes.
/// The width of the NativeWindow in pixels.
/// The height of the NativeWindow in pixels.
/// The title of the NativeWindow.
/// GameWindow options specifying window appearance and behavior.
/// The OpenTK.Graphics.GraphicsMode of the NativeWindow.
/// The OpenTK.Graphics.DisplayDevice to construct the NativeWindow in.
/// If width or height is less than 1.
/// If mode or device is null.
public NativeWindow(int width, int height, string title, GameWindowFlags options, GraphicsMode mode, DisplayDevice device)
: this(device.Bounds.Left + (device.Bounds.Width - width) / 2,
device.Bounds.Top + (device.Bounds.Height - height) / 2,
width, height, title, options, mode, device) { }
/// Constructs a new NativeWindow with the specified attributes.
/// Horizontal screen space coordinate of the NativeWindow's origin.
/// Vertical screen space coordinate of the NativeWindow's origin.
/// The width of the NativeWindow in pixels.
/// The height of the NativeWindow in pixels.
/// The title of the NativeWindow.
/// GameWindow options specifying window appearance and behavior.
/// The OpenTK.Graphics.GraphicsMode of the NativeWindow.
/// The OpenTK.Graphics.DisplayDevice to construct the NativeWindow in.
/// If width or height is less than 1.
/// If mode or device is null.
public NativeWindow(int x, int y, int width, int height, string title, GameWindowFlags options, GraphicsMode mode, DisplayDevice device) {
// TODO: Should a constraint be added for the position?
if (width < 1)
throw new ArgumentOutOfRangeException("width", "Must be greater than zero.");
if (height < 1)
throw new ArgumentOutOfRangeException("height", "Must be greater than zero.");
if (mode == null)
throw new ArgumentNullException("mode");
if (device == null)
throw new ArgumentNullException("device");
this.options = options;
this.device = device;
implementation = Factory.Default.CreateNativeWindow(x, y, width, height, title, mode, options, this.device);
if ((options & GameWindowFlags.Fullscreen) != 0) {
this.device.ChangeResolution(width, height, mode.ColorFormat.BitsPerPixel, 0);
WindowState = WindowState.Fullscreen;
}
}
/// Closes the NativeWindow.
public void Close() {
EnsureUndisposed();
implementation.Close();
}
/// Gets the current contents of the clipboard.
public string GetClipboardText() {
EnsureUndisposed(); return implementation.GetClipboardText();
}
/// Sets the current contents of the clipboard.
public void SetClipboardText(string value) {
EnsureUndisposed(); implementation.SetClipboardText(value);
}
/// Transforms the specified point from screen to client coordinates.
/// A to transform.
/// The point transformed to client coordinates.
public Point PointToClient(Point point) {
return implementation.PointToClient(point);
}
/// Transforms the specified point from client to screen coordinates.
/// A to transform.
/// The point transformed to screen coordinates.
public Point PointToScreen(Point point) {
// Here we use the fact that PointToClient just translates the point, and PointToScreen
// should perform the inverse operation.
Point trans = PointToClient(Point.Empty);
point.X -= trans.X;
point.Y -= trans.Y;
return point;
}
/// Processes operating system events until the NativeWindow becomes idle.
public void ProcessEvents() {
ProcessEvents(false);
}
/// Gets or sets a structure that contains the external bounds of this window, in screen coordinates.
/// External bounds include the title bar, borders and drawing area of the window.
public Rectangle Bounds {
get { EnsureUndisposed(); return implementation.Bounds; }
set { EnsureUndisposed(); implementation.Bounds = value; }
}
/// Gets or sets a structure that contains the internal bounds of this window, in client coordinates.
/// The internal bounds include the drawing area of the window, but exclude the titlebar and window borders.
public Rectangle ClientRectangle {
get { EnsureUndisposed(); return implementation.ClientRectangle; }
set { EnsureUndisposed(); implementation.ClientRectangle = value; }
}
/// Gets or sets a structure that contains the internal size this window.
public Size ClientSize {
get { EnsureUndisposed(); return implementation.ClientSize; }
set { EnsureUndisposed(); implementation.ClientSize = value;
}
}
/// Gets a value indicating whether a render window exists.
public bool Exists {
get {
return IsDisposed ? false : implementation.Exists; // TODO: Should disposed be ignored instead?
}
}
/// Gets a System.Boolean that indicates whether this NativeWindow has input focus.
public bool Focused {
get { EnsureUndisposed(); return implementation.Focused; }
}
/// Gets or sets the external height of this window.
public int Height {
get { EnsureUndisposed(); return implementation.Height; }
set { EnsureUndisposed(); implementation.Height = value; }
}
/// Gets or sets the System.Drawing.Icon for this GameWindow.
public Icon Icon {
get { EnsureUndisposed(); return implementation.Icon; }
set { EnsureUndisposed(); implementation.Icon = value; }
}
/// Gets or sets a structure that contains the location of this window on the desktop.
public Point Location {
get { EnsureUndisposed(); return implementation.Location; }
set { EnsureUndisposed(); implementation.Location = value; }
}
/// Gets or sets a structure that contains the external size of this window.
public Size Size {
get { EnsureUndisposed(); return implementation.Size; }
set { EnsureUndisposed(); implementation.Size = value; }
}
/// Gets or sets the NativeWindow title.
public string Title {
get { EnsureUndisposed(); return implementation.Title; }
set { EnsureUndisposed(); implementation.Title = value; }
}
/// Gets or sets a System.Boolean that indicates whether this NativeWindow is visible.
public bool Visible {
get { EnsureUndisposed(); return implementation.Visible; }
set { EnsureUndisposed(); implementation.Visible = value; }
}
/// Gets or sets the external width of this window.
public int Width {
get { EnsureUndisposed(); return implementation.Width; }
set { EnsureUndisposed(); implementation.Width = value; }
}
/// Gets the of this window.
public IWindowInfo WindowInfo {
get { EnsureUndisposed(); return implementation.WindowInfo; }
}
/// Gets or states the state of the NativeWindow.
public virtual WindowState WindowState {
get { return implementation.WindowState; }
set { implementation.WindowState = value; }
}
/// Gets or sets the horizontal location of this window on the desktop.
public int X {
get { EnsureUndisposed(); return implementation.X; }
set { EnsureUndisposed(); implementation.X = value; }
}
/// Gets or sets the vertical location of this window on the desktop.
public int Y {
get { EnsureUndisposed(); return implementation.Y; }
set { EnsureUndisposed(); implementation.Y = value; }
}
/// Gets the primary Keyboard device, or null if no Keyboard exists.
public KeyboardDevice Keyboard {
get { return implementation.Keyboard; }
}
/// Gets the primary Mouse device, or null if no Mouse exists.
public MouseDevice Mouse {
get { return implementation.Mouse; }
}
/// Sets whether the cursor is visible in the window.
public bool CursorVisible {
get { return implementation.CursorVisible; }
set { implementation.CursorVisible = value; }
}
/// Gets or sets the cursor position in screen coordinates.
public Point DesktopCursorPos {
get { return implementation.DesktopCursorPos; }
set { implementation.DesktopCursorPos = value; }
}
/// Occurs after the window has closed.
public event EventHandler Closed;
/// Occurs when the window is about to close.
public event EventHandler Closing;
/// Occurs when the window is disposed.
public event EventHandler Disposed;
/// Occurs when the property of the window changes.
public event EventHandler FocusedChanged;
/// Occurs when the property of the window changes.
public event EventHandler IconChanged;
/// Occurs whenever a character is typed.
public event EventHandler KeyPress;
/// Occurs whenever the window is moved.
public event EventHandler Move;
/// Occurs whenever the mouse cursor enters the window .
public event EventHandler MouseEnter;
/// Occurs whenever the mouse cursor leaves the window .
public event EventHandler MouseLeave;
/// Occurs whenever the window is resized.
public event EventHandler Resize;
/// Occurs when the property of the window changes.
public event EventHandler TitleChanged;
/// Occurs when the property of the window changes.
public event EventHandler VisibleChanged;
/// Occurs when the property of the window changes.
public event EventHandler WindowStateChanged;
/// Releases all non-managed resources belonging to this NativeWindow.
public virtual void Dispose() {
if (!IsDisposed) {
if ((options & GameWindowFlags.Fullscreen) != 0) {
//if (WindowState == WindowState.Fullscreen) WindowState = WindowState.Normal; // TODO: Revise.
device.RestoreResolution();
}
implementation.Dispose();
GC.SuppressFinalize(this);
IsDisposed = true;
}
}
/// Ensures that this NativeWindow has not been disposed.
/// If this NativeWindow has been disposed.
protected void EnsureUndisposed() {
if (disposed) throw new ObjectDisposedException(GetType().Name);
}
/// Gets or sets a , which indicates whether this instance has been disposed.
protected bool IsDisposed {
get { return disposed; }
set { disposed = value; }
}
/// Called when the NativeWindow has closed.
/// Not used.
protected virtual void OnClosed(object sender, EventArgs e) {
if (Closed != null) Closed(this, e);
}
/// Called when the NativeWindow is about to close.
/// The for this event.
/// Set e.Cancel to true in order to stop the NativeWindow from closing.
protected virtual void OnClosing(object sender, CancelEventArgs e) {
if (Closing != null) Closing(this, e);
}
/// Called when the NativeWindow is disposed.
protected virtual void OnDisposed(object sender, EventArgs e) {
if (Disposed != null) Disposed(this, e);
}
/// Called when the property of the NativeWindow has changed.
protected virtual void OnFocusedChanged(object sender, EventArgs e) {
if (FocusedChanged != null) FocusedChanged(this, e);
}
/// Called when the property of the NativeWindow has changed.
protected virtual void OnIconChanged(object sender, EventArgs e) {
if (IconChanged != null) IconChanged(this, e);
}
/// Called when a character is typed.
/// The for this event.
protected virtual void OnKeyPress(object sender, KeyPressEventArgs e) {
if (KeyPress != null) KeyPress(this, e);
}
/// Called when the NativeWindow is moved.
protected virtual void OnMove(object sender, EventArgs e) {
if (Move != null) Move(this, e);
}
/// Called whenever the mouse cursor reenters the window .
protected virtual void OnMouseEnter(object sender, EventArgs e) {
if (MouseEnter != null) MouseEnter(this, e);
}
/// Called whenever the mouse cursor leaves the window .
protected virtual void OnMouseLeave(object sender, EventArgs e) {
if (MouseLeave != null) MouseLeave(this, e);
}
/// Called when the NativeWindow is resized.
/// Not used.
protected virtual void OnResize(object sender, EventArgs e) {
if (Resize != null) Resize(this, e);
}
/// Called when the property of the NativeWindow has changed.
protected virtual void OnTitleChanged(object sender, EventArgs e) {
if (TitleChanged != null) TitleChanged(this, e);
}
/// Called when the property of the NativeWindow has changed.
protected virtual void OnVisibleChanged(object sender, EventArgs e) {
if (VisibleChanged != null) VisibleChanged(this, e);
}
/// Called when the WindowState of this NativeWindow has changed.
protected virtual void OnWindowStateChanged(object sender, EventArgs e) {
if (WindowStateChanged != null) WindowStateChanged(this, e);
}
/// Processes operating system events until the NativeWindow becomes idle.
/// If true, the state of underlying system event propagation will be preserved, otherwise event propagation will be enabled if it has not been already.
protected void ProcessEvents(bool retainEvents) {
EnsureUndisposed();
if (!retainEvents && !events) Events = true;
implementation.ProcessEvents();
}
private void OnClosedInternal(object sender, EventArgs e) {
OnClosed(null, e);
Events = false;
}
private bool Events {
set {
if (value) {
if (events) {
throw new InvalidOperationException("Event propagation is already enabled.");
}
implementation.Closed += OnClosed;
implementation.Closing += OnClosing;
implementation.Disposed += OnDisposed;
implementation.FocusedChanged += OnFocusedChanged;
implementation.IconChanged += OnIconChanged;
implementation.KeyPress += OnKeyPress;
implementation.MouseEnter += OnMouseEnter;
implementation.MouseLeave += OnMouseLeave;
implementation.Move += OnMove;
implementation.Resize += OnResize;
implementation.TitleChanged += OnTitleChanged;
implementation.VisibleChanged += OnVisibleChanged;
implementation.WindowStateChanged += OnWindowStateChanged;
events = true;
} else if (events) {
implementation.Closed -= OnClosed;
implementation.Closing -= OnClosing;
implementation.Disposed -= OnDisposed;
implementation.FocusedChanged -= OnFocusedChanged;
implementation.IconChanged -= OnIconChanged;
implementation.KeyPress -= OnKeyPress;
implementation.MouseEnter -= OnMouseEnter;
implementation.MouseLeave -= OnMouseLeave;
implementation.Move -= OnMove;
implementation.Resize -= OnResize;
implementation.TitleChanged -= OnTitleChanged;
implementation.VisibleChanged -= OnVisibleChanged;
implementation.WindowStateChanged -= OnWindowStateChanged;
events = false;
} else {
throw new InvalidOperationException("Event propagation is already disabled.");
}
}
}
}
}