From 7df9a448d681885cd6086dd9213718dcce658fc1 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Tue, 2 Jun 2009 15:49:39 +0000 Subject: [PATCH] Merged gw-next2 branch to trunk. --- Build/Instructions.txt | 29 +- Documentation/Release.txt | 42 +- Documentation/Todo.txt | 1 + Source/Bind/Documentation/todo.txt | 12 +- Source/Examples/OpenGL/1.1/DisplayLists.cs | 6 +- Source/Examples/OpenGL/1.1/ImmediateMode.cs | 12 +- Source/Examples/OpenGL/1.1/Textures.cs | 6 +- Source/Examples/OpenGL/1.1/VertexArrays.cs | 10 +- Source/Examples/OpenGL/1.1/VertexLighting.cs | 8 +- .../Examples/OpenGL/1.5/VertexBufferObject.cs | 8 +- .../Examples/OpenGL/EXT/FramebufferObject.cs | 6 +- .../Examples/OpenGL/GLSL/JuliaSetFractal.cs | 6 +- Source/Examples/OpenGL/GLSL/SimpleGLSL.cs | 10 +- Source/Examples/OpenGL/GLU/Tessellation.cs | 4 +- .../OpenTK/Fonts/FontRenderingAdvanced.cs | 6 +- .../OpenTK/GameWindow/FullscreenAntialias.cs | 6 +- .../OpenTK/GameWindow/SimpleWindow.cs | 8 +- .../Examples/OpenTK/Test/GameWindowStates.cs | 10 +- Source/Examples/OpenTK/Test/InputLogger.cs | 10 +- .../Examples/Properties/Resources.Designer.cs | 8 +- Source/OpenTK/DisplayMode.cs | 4 + Source/OpenTK/FrameEventArgs.cs | 70 + Source/OpenTK/GLControl.cs | 2 +- Source/OpenTK/GameWindow.cs | 1158 +++++++---- Source/OpenTK/Graphics/DisplayDevice.cs | 32 +- Source/OpenTK/Graphics/DisplayResolution.cs | 28 +- Source/OpenTK/Graphics/GraphicsContext.cs | 10 +- Source/OpenTK/Graphics/GraphicsMode.cs | 2 +- Source/OpenTK/IGameWindow.cs | 85 + Source/OpenTK/INativeWindow.cs | 226 +++ Source/OpenTK/Input/KeyboardDevice.cs | 4 +- Source/OpenTK/Platform/Factory.cs | 72 +- Source/OpenTK/Platform/IGameWindow.cs | 41 - Source/OpenTK/Platform/INativeGLWindow.cs | 3 +- Source/OpenTK/Platform/IPlatformFactory.cs | 37 +- Source/OpenTK/Platform/MacOS/Application.cs | 2 +- .../MacOS/CarbonBindings/CarbonAPI.cs | 7 + .../OpenTK/Platform/MacOS/CarbonGLNative.cs | 390 +++- Source/OpenTK/Platform/MacOS/MacOSFactory.cs | 34 +- .../MacOS/QuartzDisplayDeviceDriver.cs | 2 +- Source/OpenTK/Platform/Utilities.cs | 49 +- Source/OpenTK/Platform/Windows/API.cs | 525 +++-- .../Platform/Windows/WinDisplayDevice.cs | 13 +- Source/OpenTK/Platform/Windows/WinFactory.cs | 36 +- .../OpenTK/Platform/Windows/WinGLContext.cs | 29 +- .../OpenTK/Platform/Windows/WinGLControl.cs | 2 +- Source/OpenTK/Platform/Windows/WinGLNative.cs | 1230 +++++++----- .../OpenTK/Platform/Windows/WinWindowInfo.cs | 1 + Source/OpenTK/Platform/X11/Functions.cs | 5 + Source/OpenTK/Platform/X11/X11Factory.cs | 4 +- Source/OpenTK/Platform/X11/X11GLContext.cs | 59 +- Source/OpenTK/Platform/X11/X11GLNative.cs | 1772 +++++++++-------- .../Platform/X11/X11XrandrDisplayDevice.cs | 13 +- 53 files changed, 4005 insertions(+), 2150 deletions(-) create mode 100644 Source/OpenTK/FrameEventArgs.cs create mode 100644 Source/OpenTK/IGameWindow.cs create mode 100644 Source/OpenTK/INativeWindow.cs delete mode 100644 Source/OpenTK/Platform/IGameWindow.cs diff --git a/Build/Instructions.txt b/Build/Instructions.txt index a5141f16..6664745c 100644 --- a/Build/Instructions.txt +++ b/Build/Instructions.txt @@ -5,13 +5,34 @@ OpenTK does not require installation. Simply decompress the archive to a folder Usage -To use OpenTK, you need to reference OpenTK.dll from your project. The way you do this changes from IDE to IDE - refer to http://www.opentk.com/doc for specific instructions. +To use OpenTK, you need to reference "OpenTK.dll". Refer to http://www.opentk.com/doc for specific instructions. -In any case, make sure the OpenTK.dll.config file is copied to the output directory along with OpenTK.dll. This file is *required* for OpenTK to function on Linux and Mac OS X. +Regardless of your development environment and operating system, ensure that you copy "OpenTK.dll.config" to the output directory. Without OpenTK.dll.config, your application will not function on Linux or MacOS. Build instructions -If you have Visual Studio 2005/2008 or MonoDevelop 2 (post-beta1), simply open OpenTK.sln in the Build/ folder. If you wish build from the commandline, install nant (http://nant.sourceforge.net) and execute Build.exe in the Build/ folder. +You can build OpenTK using Visual Studio 2005+, SharpDevelop 2.0+, MonoDevelop 2.0+, msbuild or nant. Instructions: -The resulting binaries are placed into the Binaries/Release or Binaries/Debug folder. \ No newline at end of file +1a. Open the Build/ folder. + +1b. If you are using a fresh SVN checkout, double click "Build.exe", type "vs" and press enter twice to create OpenTK.sln. This step is not necessary if you are using a released version of OpenTK. + +2a. If you are using Visual Studio, SharpDevelop or MonoDevelop, double-click OpenTK.sln, select a build configuration (debug/release) and build the project. + +2b. If you wish to build from the commandline: + +[Windows] +Make sure msbuild is in your path and type: + +cd Build +Build.exe vs +msbuild + +[Linux / MacOS] +Make sure nant (http://nant.sourceforge.net) is in your path and type: + +cd Build/ +mono Build.exe nant release + +4. The resulting binaries are placed into the Binaries/Release or Binaries/Debug folder. \ No newline at end of file diff --git a/Documentation/Release.txt b/Documentation/Release.txt index 8d8d4083..a4984566 100644 --- a/Documentation/Release.txt +++ b/Documentation/Release.txt @@ -38,6 +38,7 @@ To visit an issue report, type "http://www.opentk.com/node/{id}", where {id} is [#870] + [Known issues] Mono 2.2 and 2.4 cannot compile this release (bug report: https://bugzilla.novell.com/show_bug.cgi?id=488960). Please compile with Mono 2.0 or 2.4.2+, or use the precompiled binaries. @@ -46,13 +47,48 @@ OpenTK.Graphics.TextPrinter fails to render text with newlines or a layout recta Example documentation may not show up correctly when running on Mono. +Joystick input is not supported on MacOS at this time. + +OpenGL 3.0 is not supported on MacOS at this time. + + [API changes] Please note that binary compatibility is not preserved between beta releases. -OpenTK 0.9.8 replaces several instances of the "All" and "Version*" enums with strongly-typed equivalents. This is a breaking change. If you are affected by this change, replace these enums with the ones suggested by your compiler. -OpenTK 0.9.8 removes several OpenGL overloads that take arrays of a single item. This is a breaking change. If you are affected by this change, please use the 'ref' or 'out' overload for the relevant function. +[0.9.9] -OpenTK 0.9.8 removes or replaces several invalid tokens in the DrawBuffer(s) methods. This is a breaking change. \ No newline at end of file +1. GameWindow.Resize and GameWindow.OnResize have changed signatures: + +ResizeEventHandler Resize(object, ResizeEventArgs) -> EventHandler Resize(object, EventArgs) +OnResize(ResizeEventArgs) -> OnResize(EventArgs) + +Please replace all instances of "ResizeEventHandler" by "EventHandler and replace "e.Width" / "e.Height" by "this.Width" and "this.Height". + + +[0.9.8] + +1. OpenTK 0.9.8 replaces several instances of the "All" and "Version*" enums with strongly-typed equivalents. This is a breaking change. If you are affected by this change, replace these enums with the ones suggested by your compiler. + +The 'v' suffix has been removed from several OpenTK.Graphics.GL functions. Please search and replace any of the following functions (list non-inclusive): + +Uniform1v -> Uniform1 +Materialv -> Material +Lightv -> Light + + +2. Several instances of the "Version12" enum have been replaced with strongly-typed equivalents. This is a breaking change that affects programs using the imaging subset of OpenGL 1.2. + +If you are affected by this change, please replace all relevant instances of "Version12" with the correct enum, as indicated by your compiler. + + +3. OpenTK 0.9.8 removes several OpenGL overloads that take arrays of a single item. This is a breaking change. If you are affected by this change, please use the 'ref' or 'out' overload for the relevant function. + + +[0.9.7] + +OpenTK 0.9.7 replaces several instances of the "All" and "Version30" enums with strongly-typed equivalents. This is a breaking change that potentially affects programs using OpenGL 3.0 functionality. If you are affected by this change, please replace the relevant instances of "All" or "Version30" with the correct enum, as reported by your IDE. + +OpenTK 0.9.7 also fixes the naming of several core and extension functions ending in "Instanced", "Indexed" or "Varyings". If you are affected by this change, please add the missing 'd' or 's' to the relevant functions. diff --git a/Documentation/Todo.txt b/Documentation/Todo.txt index 5dc45091..dc03df72 100644 --- a/Documentation/Todo.txt +++ b/Documentation/Todo.txt @@ -12,6 +12,7 @@ [OpenTK.Graphics.GraphicsContext] + FSAA support (very simple, now that GL3 support has been added.) + Implement GL3 support on Mac OS X. ++ Improve API for context sharing (add a sharedContext parameter to the context constructor). [OpenTK.GLControl] + Improve the designer interface. diff --git a/Source/Bind/Documentation/todo.txt b/Source/Bind/Documentation/todo.txt index 16f93677..d922f9cb 100644 --- a/Source/Bind/Documentation/todo.txt +++ b/Source/Bind/Documentation/todo.txt @@ -1,11 +1,3 @@ -OpenTK.OpenGL.Bind 0.9.4 todos: - -Major: -+ Change the output of extensions from GL.BlahARB to GL.ARB.Blah -+ Use generics instead of object overloads. -+ Add ref overloads for arrays - Minor: -+ Clean up the reader. -+ Add more settings to Settings.cs (the name of the files to read). -+ Comment the code. ++ Improve inline documentation for function overloads (parameters are incorrect). ++ Clean up the code. diff --git a/Source/Examples/OpenGL/1.1/DisplayLists.cs b/Source/Examples/OpenGL/1.1/DisplayLists.cs index f31f03a4..304941c1 100644 --- a/Source/Examples/OpenGL/1.1/DisplayLists.cs +++ b/Source/Examples/OpenGL/1.1/DisplayLists.cs @@ -95,7 +95,7 @@ namespace Examples.Tutorial #region OnResize - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); @@ -111,7 +111,7 @@ namespace Examples.Tutorial #region OnUpdateFrame - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[OpenTK.Input.Key.Escape]) { @@ -123,7 +123,7 @@ namespace Examples.Tutorial #region OnRenderFrame - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.MatrixMode(MatrixMode.Modelview); GL.LoadIdentity(); diff --git a/Source/Examples/OpenGL/1.1/ImmediateMode.cs b/Source/Examples/OpenGL/1.1/ImmediateMode.cs index 39e7257f..0215c90b 100644 --- a/Source/Examples/OpenGL/1.1/ImmediateMode.cs +++ b/Source/Examples/OpenGL/1.1/ImmediateMode.cs @@ -63,13 +63,11 @@ namespace Examples.Tutorial /// /// You want the OpenGL viewport to match the window. This is the place to do it! /// - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { - base.OnResize(e); - GL.Viewport(0, 0, Width, Height); - double aspect_ratio = e.Width / (double)e.Height; + double aspect_ratio = Width / (double)Height; GL.MatrixMode(MatrixMode.Projection); if (Keyboard[OpenTK.Input.Key.Space]) @@ -95,7 +93,7 @@ namespace Examples.Tutorial /// Place your control logic here. This is the place to respond to user input, /// update object positions etc. /// - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[OpenTK.Input.Key.Escape]) { @@ -111,7 +109,7 @@ namespace Examples.Tutorial /// /// Place your rendering code here. /// - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); @@ -121,7 +119,7 @@ namespace Examples.Tutorial 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - angle += rotation_speed * (float)e.ScaleFactor; + angle += rotation_speed * (float)e.Time; GL.Rotate(angle, 0.0f, 1.0f, 0.0f); DrawCube(); diff --git a/Source/Examples/OpenGL/1.1/Textures.cs b/Source/Examples/OpenGL/1.1/Textures.cs index caf9b1ec..112c1c3d 100644 --- a/Source/Examples/OpenGL/1.1/Textures.cs +++ b/Source/Examples/OpenGL/1.1/Textures.cs @@ -77,7 +77,7 @@ namespace Examples.Tutorial /// /// Contains information on the new GameWindow size. /// There is no need to call the base implementation. - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); @@ -95,7 +95,7 @@ namespace Examples.Tutorial /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit(); @@ -110,7 +110,7 @@ namespace Examples.Tutorial /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenGL/1.1/VertexArrays.cs b/Source/Examples/OpenGL/1.1/VertexArrays.cs index fde9a513..3bf18bda 100644 --- a/Source/Examples/OpenGL/1.1/VertexArrays.cs +++ b/Source/Examples/OpenGL/1.1/VertexArrays.cs @@ -84,13 +84,13 @@ namespace Examples.Tutorial /// /// You want the OpenGL viewport to match the window. This is the place to do it! /// - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { base.OnResize(e); GL.Viewport(0, 0, Width, Height); - double ratio = e.Width / (double)e.Height; + double ratio = Width / (double)Height; GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); @@ -108,7 +108,7 @@ namespace Examples.Tutorial /// Place your control logic here. This is the place to respond to user input, /// update object positions etc. /// - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { // Escape quits. if (Keyboard[Key.Escape]) @@ -143,7 +143,7 @@ namespace Examples.Tutorial /// /// Place your rendering code here. /// - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); @@ -155,7 +155,7 @@ namespace Examples.Tutorial 0.0, 1.0, 0.0 ); - angle += rotation_speed * (float)e.ScaleFactor; + angle += rotation_speed * (float)e.Time; if (angle >= 360.0f) angle -= 360.0f; diff --git a/Source/Examples/OpenGL/1.1/VertexLighting.cs b/Source/Examples/OpenGL/1.1/VertexLighting.cs index 4b8df942..a3a83ada 100644 --- a/Source/Examples/OpenGL/1.1/VertexLighting.cs +++ b/Source/Examples/OpenGL/1.1/VertexLighting.cs @@ -78,13 +78,13 @@ namespace Examples.Tutorial /// /// You want the OpenGL viewport to match the window. This is the place to do it! /// - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { base.OnResize(e); GL.Viewport(0, 0, Width, Height); - double ratio = e.Width / (double)e.Height; + double ratio = Width / (double)Height; GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); @@ -102,7 +102,7 @@ namespace Examples.Tutorial /// Place your control logic here. This is the place to respond to user input, /// update object positions etc. /// - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[OpenTK.Input.Key.Escape]) { @@ -138,7 +138,7 @@ namespace Examples.Tutorial /// /// Place your rendering code here. /// - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); diff --git a/Source/Examples/OpenGL/1.5/VertexBufferObject.cs b/Source/Examples/OpenGL/1.5/VertexBufferObject.cs index a2d7bc1d..e07a4f16 100644 --- a/Source/Examples/OpenGL/1.5/VertexBufferObject.cs +++ b/Source/Examples/OpenGL/1.5/VertexBufferObject.cs @@ -73,11 +73,11 @@ namespace Examples.Tutorial #region OnResize override - protected override void OnResize(ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); - double ratio = e.Width / (double)e.Height; + double ratio = Width / (double)Height; GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); @@ -95,7 +95,7 @@ namespace Examples.Tutorial /// Place your control logic here. This is the place to respond to user input, /// update object positions etc. /// - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit(); @@ -105,7 +105,7 @@ namespace Examples.Tutorial #region OnRenderFrame - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { base.OnRenderFrame(e); diff --git a/Source/Examples/OpenGL/EXT/FramebufferObject.cs b/Source/Examples/OpenGL/EXT/FramebufferObject.cs index b9ff7e7a..5a15f4a0 100644 --- a/Source/Examples/OpenGL/EXT/FramebufferObject.cs +++ b/Source/Examples/OpenGL/EXT/FramebufferObject.cs @@ -216,7 +216,7 @@ namespace Examples.Tutorial GL.Ext.DeleteFramebuffers(1, ref FBOHandle); } - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); GL.MatrixMode(MatrixMode.Projection); @@ -230,7 +230,7 @@ namespace Examples.Tutorial base.OnResize(e); } - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); @@ -244,7 +244,7 @@ namespace Examples.Tutorial this.Exit(); } - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); diff --git a/Source/Examples/OpenGL/GLSL/JuliaSetFractal.cs b/Source/Examples/OpenGL/GLSL/JuliaSetFractal.cs index f4e2f776..527d790f 100644 --- a/Source/Examples/OpenGL/GLSL/JuliaSetFractal.cs +++ b/Source/Examples/OpenGL/GLSL/JuliaSetFractal.cs @@ -211,7 +211,7 @@ namespace Examples.Tutorial /// /// Contains information on the new GameWindow size. /// There is no need to call the base implementation. - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { // Magic numbers so the fractal almost fits inside the window. // If changing this, also change the -1.6f offset in the fragment shader accordingly. @@ -237,7 +237,7 @@ namespace Examples.Tutorial /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); @@ -256,7 +256,7 @@ namespace Examples.Tutorial /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { //this.Title = "FPS: " + 1 / e.Time; GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenGL/GLSL/SimpleGLSL.cs b/Source/Examples/OpenGL/GLSL/SimpleGLSL.cs index 092a0197..deabbc5a 100644 --- a/Source/Examples/OpenGL/GLSL/SimpleGLSL.cs +++ b/Source/Examples/OpenGL/GLSL/SimpleGLSL.cs @@ -192,11 +192,11 @@ namespace Examples.Tutorial /// /// You want the OpenGL viewport to match the window. This is the place to do it! /// - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); - double ratio = e.Width / (double)e.Height; + double ratio = Width / (double)Height; GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); @@ -214,7 +214,7 @@ namespace Examples.Tutorial /// Place your control logic here. This is the place to respond to user input, /// update object positions etc. /// - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit(); @@ -234,7 +234,7 @@ namespace Examples.Tutorial /// /// Place your rendering code here. /// - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); @@ -245,7 +245,7 @@ namespace Examples.Tutorial 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); - angle += rotation_speed * (float)e.ScaleFactor; + angle += rotation_speed * (float)e.Time; GL.Rotate(angle, 0.0f, 1.0f, 0.0f); GL.EnableClientState(EnableCap.VertexArray); diff --git a/Source/Examples/OpenGL/GLU/Tessellation.cs b/Source/Examples/OpenGL/GLU/Tessellation.cs index ca783b0c..5431626f 100644 --- a/Source/Examples/OpenGL/GLU/Tessellation.cs +++ b/Source/Examples/OpenGL/GLU/Tessellation.cs @@ -135,7 +135,7 @@ namespace Examples #region OnResize - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); GL.MatrixMode(MatrixMode.Projection); @@ -246,7 +246,7 @@ namespace Examples #region OnRenderFrame - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenTK/Fonts/FontRenderingAdvanced.cs b/Source/Examples/OpenTK/Fonts/FontRenderingAdvanced.cs index 3ee078d8..6d3f3d76 100644 --- a/Source/Examples/OpenTK/Fonts/FontRenderingAdvanced.cs +++ b/Source/Examples/OpenTK/Fonts/FontRenderingAdvanced.cs @@ -75,7 +75,7 @@ namespace Examples.Tutorial #region OnResize - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); @@ -87,7 +87,7 @@ namespace Examples.Tutorial #region OnUpdateFrame - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { if (Keyboard[Key.Space]) scroll_speed = 0; @@ -103,7 +103,7 @@ namespace Examples.Tutorial #region OnRenderFrame - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenTK/GameWindow/FullscreenAntialias.cs b/Source/Examples/OpenTK/GameWindow/FullscreenAntialias.cs index 93bfc487..41f19096 100644 --- a/Source/Examples/OpenTK/GameWindow/FullscreenAntialias.cs +++ b/Source/Examples/OpenTK/GameWindow/FullscreenAntialias.cs @@ -96,7 +96,7 @@ namespace Examples /// /// Contains information on the new GameWindow size. /// There is no need to call the base implementation. - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); @@ -116,7 +116,7 @@ namespace Examples /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { // Nothing to do! } @@ -130,7 +130,7 @@ namespace Examples /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenTK/GameWindow/SimpleWindow.cs b/Source/Examples/OpenTK/GameWindow/SimpleWindow.cs index 2172ece8..ecd157c9 100644 --- a/Source/Examples/OpenTK/GameWindow/SimpleWindow.cs +++ b/Source/Examples/OpenTK/GameWindow/SimpleWindow.cs @@ -68,15 +68,13 @@ namespace Examples.Tutorial /// /// Contains information on the new GameWindow size. /// There is no need to call the base implementation. - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); GL.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 4.0); - - base.OnResize(e); } #endregion @@ -88,7 +86,7 @@ namespace Examples.Tutorial /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnUpdateFrame(UpdateFrameEventArgs e) + protected override void OnUpdateFrame(FrameEventArgs e) { // Nothing to do! } @@ -102,7 +100,7 @@ namespace Examples.Tutorial /// /// Contains timing information. /// There is no need to call the base implementation. - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 62b99150..20f5ca49 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -28,8 +28,7 @@ namespace Examples.Tests T GetNext(T t) { if (!(t is Enum)) - throw new ArgumentException(String.Format("Should be an Enum type (is {0}).", t.GetType().ToString()), - "t"); + throw new ArgumentException(String.Format("Should be an Enum type (is {0}).", t.GetType().ToString()), "t"); string[] names = Enum.GetNames(t.GetType()); T[] values = (T[])Enum.GetValues(t.GetType()); @@ -45,8 +44,7 @@ namespace Examples.Tests T GetPrevious(T t) { if (!(t is Enum)) - throw new ArgumentException(String.Format("Should be an Enum type (is {0}).", t.GetType().ToString()), - "t"); + throw new ArgumentException(String.Format("Should be an Enum type (is {0}).", t.GetType().ToString()), "t"); string[] names = Enum.GetNames(t.GetType()); T[] values = (T[])Enum.GetValues(t.GetType()); @@ -111,12 +109,12 @@ namespace Examples.Tests } } - protected override void OnResize(OpenTK.Platform.ResizeEventArgs e) + protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); } - public override void OnRenderFrame(RenderFrameEventArgs e) + protected override void OnRenderFrame(FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); diff --git a/Source/Examples/OpenTK/Test/InputLogger.cs b/Source/Examples/OpenTK/Test/InputLogger.cs index 0aba80fb..a80ab8d5 100644 --- a/Source/Examples/OpenTK/Test/InputLogger.cs +++ b/Source/Examples/OpenTK/Test/InputLogger.cs @@ -51,24 +51,24 @@ namespace Examples.Tests hidden = new GameWindow(320, 240, GraphicsMode.Default, "OpenTK | Hidden input window"); hidden.Load += hidden_Load; hidden.Unload += hidden_Unload; - hidden.RenderFrame += new OpenTK.RenderFrameEvent(hidden_RenderFrame); + hidden.RenderFrame += hidden_RenderFrame; hidden.Run(60.0, 0.0); } - void hidden_RenderFrame(GameWindow sender, RenderFrameEventArgs e) + void hidden_RenderFrame(object sender, FrameEventArgs e) { GL.Clear(ClearBufferMask.ColorBufferBit); - sender.SwapBuffers(); + ((GameWindow)sender).SwapBuffers(); } - void hidden_Load(GameWindow sender, EventArgs e) + void hidden_Load(object sender, EventArgs e) { hidden.VSync = VSyncMode.On; start = true; GL.ClearColor(Color.Black); } - void hidden_Unload(GameWindow sender, EventArgs e) + void hidden_Unload(object sender, EventArgs e) { this.BeginInvoke(on_hidden_unload, sender, e, this); } diff --git a/Source/Examples/Properties/Resources.Designer.cs b/Source/Examples/Properties/Resources.Designer.cs index d353c437..9b6b7ea1 100644 --- a/Source/Examples/Properties/Resources.Designer.cs +++ b/Source/Examples/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:2.0.50727.4918 +// Runtime Version:4.0.20506.1 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -19,7 +19,7 @@ namespace Examples.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -579,9 +579,7 @@ namespace Examples.Properties { ///using System.Diagnostics; /// ///using OpenTK; - ///using OpenTK.Graphics.OpenGL; ///using OpenTK.Graphics; - ///using OpenTK.Graphics.OpenGL.Enums; ///using OpenTK.Input; /// ///namespace Examples.Tutorial @@ -589,7 +587,7 @@ namespace Examples.Properties { /// /// <summary> /// /// Demonstrates the GameWindow class. /// /// </summary> - /// [Exampl [rest of string was truncated]";. + /// [Example("Simple Window", ExampleCategory.OpenTK, "GameWindow", Documentati [rest of string was truncated]";. /// internal static string SimpleWindow { get { diff --git a/Source/OpenTK/DisplayMode.cs b/Source/OpenTK/DisplayMode.cs index 7b94579d..df9abc5b 100644 --- a/Source/OpenTK/DisplayMode.cs +++ b/Source/OpenTK/DisplayMode.cs @@ -307,11 +307,15 @@ namespace OpenTK #endregion + #region --- Internal Members --- + internal GraphicsMode ToGraphicsMode() { return new GraphicsMode(this.Color.BitsPerPixel, this.DepthBits, this.StencilBits, 0, this.AuxBits, this.Buffers, this.Stereo); } + #endregion + #region --- Overrides --- /// diff --git a/Source/OpenTK/FrameEventArgs.cs b/Source/OpenTK/FrameEventArgs.cs new file mode 100644 index 00000000..d5184215 --- /dev/null +++ b/Source/OpenTK/FrameEventArgs.cs @@ -0,0 +1,70 @@ +#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; + +namespace OpenTK +{ + /// + /// Defines the arguments for frame events. + /// A FrameEventArgs instance is only valid for the duration of the relevant event; + /// do not store references to FrameEventArgs outside this event. + /// + public class FrameEventArgs : EventArgs + { + double elapsed; + + /// + /// Constructs a new FrameEventArgs instance. + /// + public FrameEventArgs() + { } + + /// + /// Constructs a new FrameEventArgs instance. + /// + /// The amount of time that has elapsed since the previous event, in seconds. + public FrameEventArgs(double elapsed) + { + Time = elapsed; + } + + /// + /// Gets a that indicates how many seconds of time elapsed since the previous event. + /// + public double Time + { + get { return elapsed; } + internal set + { + if (value <= 0) + throw new ArgumentOutOfRangeException(); + elapsed = value; + } + } + } +} diff --git a/Source/OpenTK/GLControl.cs b/Source/OpenTK/GLControl.cs index d1983566..aab0c92e 100644 --- a/Source/OpenTK/GLControl.cs +++ b/Source/OpenTK/GLControl.cs @@ -81,7 +81,7 @@ namespace OpenTK if (DesignMode) implementation = new Platform.Dummy.DummyGLControl(); else - implementation = Platform.Factory.CreateGLControl(mode, this); + implementation = Platform.Factory.Default.CreateGLControl(mode, this); this.CreateControl(); } diff --git a/Source/OpenTK/GameWindow.cs b/Source/OpenTK/GameWindow.cs index 29e999da..d14c6f58 100644 --- a/Source/OpenTK/GameWindow.cs +++ b/Source/OpenTK/GameWindow.cs @@ -1,23 +1,39 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK Team. - * This notice may not be removed from any source distribution. - * See license.txt for licensing details. - */ +#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.Collections.Generic; -using System.Text; +using System.ComponentModel; using System.Diagnostics; using System.Threading; - -using OpenTK.Platform; -using OpenTK.Input; -using OpenTK.Graphics.OpenGL; -using OpenTK.Graphics.OpenGL.Enums; using OpenTK.Graphics; -using System.ComponentModel; +using OpenTK.Input; +using OpenTK.Platform; +using System.Drawing; namespace OpenTK { @@ -53,15 +69,13 @@ namespace OpenTK /// parameters that /// specify the logic update rate, and the render update rate. /// - public class GameWindow : IDisposable/* : IGameWindow*/ + public class GameWindow : IGameWindow { #region --- Fields --- - INativeGLWindow glWindow; + INativeWindow glWindow; //DisplayMode mode; - ResizeEventArgs resizeEventArgs = new ResizeEventArgs(); - bool isExiting = false; bool hasMainLoop; bool disposed; @@ -71,7 +85,6 @@ namespace OpenTK // TODO: Implement these: double update_time, render_time;//, event_time; //bool allow_sleep = true; // If true, GameWindow will call Timer.Sleep() if there is enough time. - int width, height; VSyncMode vsync; //InputDriver input_driver; @@ -156,7 +169,7 @@ namespace OpenTK #region public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, GraphicsContextFlags flags) - /// Constructs a new GameWindow with the specified attributes. + /// Constructs a new GameWindow with the specified attributes. /// The width of the GameWindow in pixels. /// The height of the GameWindow in pixels. /// The OpenTK.Graphics.GraphicsMode of the GameWindow. @@ -168,42 +181,73 @@ namespace OpenTK /// The GraphicsContextFlags version for the OpenGL GraphicsContext. public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, GraphicsContextFlags flags) + : this(width, height, mode, title, options, device, major, minor, flags, null) + { } + + #endregion + + #region public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, int major, int minor, GraphicsContextFlags flags, IGraphicsContext sharedContext) + + /// Constructs a new GameWindow with the specified attributes. + /// The width of the GameWindow in pixels. + /// The height of the GameWindow in pixels. + /// The OpenTK.Graphics.GraphicsMode of the GameWindow. + /// The title of the GameWindow. + /// GameWindow options regarding window appearance and behavior. + /// The OpenTK.Graphics.DisplayDevice to construct the GameWindow in. + /// The major version for the OpenGL GraphicsContext. + /// The minor version for the OpenGL GraphicsContext. + /// The GraphicsContextFlags version for the OpenGL GraphicsContext. + /// An IGraphicsContext to share resources with. + public GameWindow(int width, int height, GraphicsMode mode, string title, GameWindowFlags options, DisplayDevice device, + int major, int minor, GraphicsContextFlags flags, IGraphicsContext sharedContext) { - if (width <= 0) throw new ArgumentOutOfRangeException("width", "Must be greater than zero."); - if (height <= 0) throw new ArgumentOutOfRangeException("width", "Must be greater than zero."); + if (width <= 0) + throw new ArgumentOutOfRangeException("width", "Must be greater than zero."); + if (height <= 0) + throw new ArgumentOutOfRangeException("height", "Must be greater than zero."); if (mode == null) mode = GraphicsMode.Default; if (device == null) device = DisplayDevice.Default; - glWindow = Platform.Factory.CreateNativeGLWindow(); - glWindow.Destroy += glWindow_Destroy; - try { - glWindow.CreateWindow(width, height, mode, major, minor, flags, out glContext); + Rectangle window_bounds = new Rectangle(); + window_bounds.X = device.Bounds.Left + (device.Bounds.Width - width) / 2; + window_bounds.Y = device.Bounds.Top + (device.Bounds.Height - height) / 2; + window_bounds.Width = width; + window_bounds.Height = height; + glWindow = Platform.Factory.Default.CreateNativeWindow( + window_bounds.X, window_bounds.Y, + window_bounds.Width, window_bounds.Height, + title, mode, options, device); + + glContext = new GraphicsContext(mode, glWindow.WindowInfo, major, minor, flags); glContext.MakeCurrent(this.WindowInfo); (glContext as IGraphicsContextInternal).LoadAll(); + + if ((options & GameWindowFlags.Fullscreen) != 0) + { + device.ChangeResolution(width, height, mode.ColorFormat.BitsPerPixel, 0); + this.WindowState = WindowState.Fullscreen; + } + + this.VSync = VSyncMode.On; + + glWindow.Move += delegate(object sender, EventArgs e) { OnMoveInternal(e); }; + glWindow.Resize += delegate(object sender, EventArgs e) { OnResizeInternal(e); }; + glWindow.Closing += delegate(object sender, CancelEventArgs e) { OnClosingInternal(e); }; + glWindow.Closed += delegate(object sender, EventArgs e) { OnClosedInternal(e); }; + //glWindow.WindowInfoChanged += delegate(object sender, EventArgs e) { OnWindowInfoChangedInternal(e); }; } - //catch (GraphicsContextException e) catch (Exception e) { Debug.Print(e.ToString()); - glWindow.DestroyWindow(); + if (glWindow != null) + glWindow.Dispose(); throw; } - - this.Title = title; - - if ((options & GameWindowFlags.Fullscreen) != 0) - { - device.ChangeResolution(width, height, mode.ColorFormat.BitsPerPixel, 0); - this.WindowState = WindowState.Fullscreen; - //throw new NotImplementedException(); - } - - this.VSync = VSyncMode.On; //VSyncMode.Adaptive; - glWindow.Resize += delegate(object sender, ResizeEventArgs e) { OnResizeInternal(e); }; } #endregion @@ -234,16 +278,6 @@ namespace OpenTK #region --- Private Methods --- - #region void glWindow_Destroy(object sender, EventArgs e) - - void glWindow_Destroy(object sender, EventArgs e) - { - glWindow.Destroy -= glWindow_Destroy; - ExitAsync(); - } - - #endregion - #region void ExitInternal() // Stops the main loop, if one exists. @@ -260,17 +294,12 @@ namespace OpenTK // Gracefully exits the GameWindow. May be called from any thread. void ExitAsync() { - if (disposed) - throw new ObjectDisposedException("GameWindow"); - - UpdateFrame += CallExitInternal; - } - - // Used in ExitAsync() to ensure ExitInternal() is called from the main thread. - void CallExitInternal(GameWindow sender, UpdateFrameEventArgs e) - { - UpdateFrame -= CallExitInternal; - sender.ExitInternal(); + HasMainLoop = false; + isExiting = true; + //UpdateFrame += delegate + //{ + // ExitInternal(); + //}; } #endregion @@ -296,6 +325,159 @@ namespace OpenTK #endregion + #region OnMoveInternal + + // Calls OnMove and raises the Move event. + void OnMoveInternal(EventArgs e) + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + if (!this.Exists || this.IsExiting) + return; + + OnMove(e); + + if (Move != null) + Move(this, e); + } + + #endregion + + #region OnResizeInternal + + // Calls OnResize and raises the Resize event. + void OnResizeInternal(EventArgs e) + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + if (!this.Exists || this.IsExiting) + return; + + OnResize(e); + + if (Resize != null) + Resize(this, e); + } + + #endregion + + #region OnClosingInternal + + void OnClosingInternal(CancelEventArgs e) + { + OnClosing(e); + + if (Closing != null) + Closing(this, e); + + if (!e.Cancel) + ExitAsync(); + } + + #endregion + + #region OnClosedInternal + + void OnClosedInternal(EventArgs e) + { + OnClosed(e); + + if (Closed != null) + Closed(this, e); + } + + #endregion + + #region OnWindowInfoChangedInternal + + void OnWindowInfoChangedInternal(EventArgs e) + { + glContext.MakeCurrent(WindowInfo); + + OnWindowInfoChanged(e); + } + + #endregion + + #region OnUpdateFrameInternal + + private void OnUpdateFrameInternal(FrameEventArgs e) + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + if (!this.Exists || this.IsExiting) + return; + + if (UpdateFrame != null) + UpdateFrame(this, e); + + OnUpdateFrame(e); + } + + #endregion + + #region OnRenderFrameInternal + + private void OnRenderFrameInternal(FrameEventArgs e) + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + if (!this.Exists || this.IsExiting) + return; + + if (RenderFrame != null) + RenderFrame(this, e); + + OnRenderFrame(e); + } + + #endregion + + #endregion + + #region --- Protected Members --- + + /// + /// Called when the GameWindow is moved. + /// + /// Not used. + protected virtual void OnMove(EventArgs e) + { } + + /// + /// Called when the GameWindow is resized. + /// + /// Not used. + protected virtual void OnResize(EventArgs e) + { } + + /// + /// Called when the GameWindow is about to close. + /// + /// + /// The for this event. + /// Set e.Cancel to true in order to stop the GameWindow from closing. + protected virtual void OnClosing(CancelEventArgs e) + { } + + /// + /// Called when the GameWindow has closed. + /// + /// Not used. + protected virtual void OnClosed(EventArgs e) + { } + + /// + /// Called when the WindowInfo for this GameWindow has changed. + /// + /// Not used. + protected virtual void OnWindowInfoChanged(EventArgs e) + { } + #endregion #region --- Public Members --- @@ -314,15 +496,17 @@ namespace OpenTK lock (exit_lock) { if (disposed) - throw new ObjectDisposedException("GameWindow"); + throw new ObjectDisposedException(this.GetType().Name); if (!IsExiting && Exists) { CancelEventArgs e = new CancelEventArgs(); - Closing(this, e); + OnClosingInternal(e); if (e.Cancel) return; - + + isExiting = true; + if (HasMainLoop) { if (main_loop_thread_id == Thread.CurrentThread.ManagedThreadId) @@ -336,33 +520,6 @@ namespace OpenTK #endregion - #region public bool IsIdle - - /// - /// Gets a value indicating whether the current GameWindow is idle. - /// If true, the OnUpdateFrame and OnRenderFrame functions should be called. - /// - public bool IsIdle - { - get { if (disposed) throw new ObjectDisposedException("GameWindow"); return glWindow.IsIdle; } - } - - #endregion - - #region public bool Fullscreen - - ///// - ///// TODO: This property is not implemented. - ///// Gets or sets a value indicating whether the GameWindow is in fullscrren mode. - ///// - //public bool Fullscreen - //{ - // get { if (disposed) throw new ObjectDisposedException("GameWindow"); return glWindow.Fullscreen; } - // set { if (disposed) throw new ObjectDisposedException("GameWindow"); glWindow.Fullscreen = value; } - //} - - #endregion - #region public IGraphicsContext Context /// @@ -372,7 +529,8 @@ namespace OpenTK { get { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); return glContext; } } @@ -400,12 +558,12 @@ namespace OpenTK { get { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) throw new ObjectDisposedException(this.GetType().Name); return glWindow.Title; } set { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) throw new ObjectDisposedException(this.GetType().Name); glWindow.Title = value; } } @@ -446,12 +604,12 @@ namespace OpenTK #region public void Run() /// - /// Enters the game loop of the GameWindow updating and rendering at the maximum possible frequency. + /// Enters the game loop of the GameWindow using the maximum update rate. /// - /// + /// public void Run() { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) throw new ObjectDisposedException(this.GetType().Name); Run(0.0, 0.0); } @@ -460,14 +618,15 @@ namespace OpenTK #region public void Run(double updateFrequency) /// - /// Enters the game loop of the GameWindow updating the specified update frequency, while maintaining the + /// Enters the game loop of the GameWindow using the specified update rate. /// maximum possible render frequency. /// - /// - public void Run(double updateFrequency) + public void Run(double updateRate) { - if (disposed) throw new ObjectDisposedException("GameWindow"); - Run(updateFrequency, 0.0); + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + Run(updateRate, 0.0); } #endregion @@ -482,7 +641,7 @@ namespace OpenTK public void Run(double updates_per_second, double frames_per_second) { if (disposed) - throw new ObjectDisposedException("GameWindow"); + throw new ObjectDisposedException(this.GetType().Name); try { @@ -503,35 +662,17 @@ namespace OpenTK Stopwatch update_watch = new Stopwatch(), render_watch = new Stopwatch(); double time, next_render = 0.0, next_update = 0.0, update_time_counter = 0.0; int num_updates = 0; - UpdateFrameEventArgs update_args = new UpdateFrameEventArgs(); - RenderFrameEventArgs render_args = new RenderFrameEventArgs(); + FrameEventArgs update_args = new FrameEventArgs(); + FrameEventArgs render_args = new FrameEventArgs(); update_watch.Reset(); render_watch.Reset(); - //double sleep_granularity; // In seconds. - - //GC.Collect(2); - //GC.WaitForPendingFinalizers(); - //GC.Collect(2); - - // Find the minimum granularity of the Thread.Sleep() function. - // TODO: Disabled - see comment on Thread.Sleep() problems below. - //update_watch.Start(); - //const int test_times = 5; - //for (int i = test_times; --i > 0; ) - // Thread.Sleep(1); - //update_watch.Stop(); - //sleep_granularity = System.Math.Round(1000.0 * update_watch.Elapsed.TotalSeconds / test_times, MidpointRounding.AwayFromZero) / 1000.0; - //update_watch.Reset(); // We don't want to affect the first UpdateFrame! - OnLoadInternal(EventArgs.Empty); - - //Debug.Print("Elevating priority."); - //Thread.CurrentThread.Priority = ThreadPriority.AboveNormal; + OnResizeInternal(EventArgs.Empty); Debug.Print("Entering main loop."); - while (!isExiting) + while (!IsExiting && HasMainLoop) { ProcessEvents(); @@ -551,10 +692,12 @@ namespace OpenTK update_watch.Reset(); update_watch.Start(); - update_args.Time = time; - OnUpdateFrameInternal(update_args); - update_time = update_watch.Elapsed.TotalSeconds; - + if (time > 0) + { + update_args.Time = time; + OnUpdateFrameInternal(update_args); + update_time = update_watch.Elapsed.TotalSeconds; + } if (TargetUpdateFrequency == 0.0) break; @@ -597,19 +740,13 @@ namespace OpenTK render_watch.Reset(); render_watch.Start(); - render_period = render_args.Time = time; - render_args.ScaleFactor = RenderPeriod / UpdatePeriod; - OnRenderFrameInternal(render_args); - render_time = render_watch.Elapsed.TotalSeconds; + if (time > 0) + { + render_period = render_args.Time = time; + OnRenderFrameInternal(render_args); + render_time = render_watch.Elapsed.TotalSeconds; + } } - - // Yield CPU time, if the Thread.Sleep() granularity allows it. - // TODO: Disabled because it does not work reliably enough on all systems. - // Enable vsync as a workaround. - //if (AllowSleep && next_render > sleep_granularity && next_update > sleep_granularity) - //{ - // Thread.Sleep((int)(1000.0 * System.Math.Min(next_render - sleep_granularity, next_update - sleep_granularity))); - //} } } catch (GameWindowExitException) @@ -627,10 +764,12 @@ namespace OpenTK { glContext.Dispose(); glContext = null; - glWindow.DestroyWindow(); + + glWindow.Dispose(); + while (this.Exists) + this.ProcessEvents(); + glWindow = null; } - while (this.Exists) - this.ProcessEvents(); } } @@ -651,35 +790,15 @@ namespace OpenTK /// public void ProcessEvents() { - if (disposed) throw new ObjectDisposedException("GameWindow"); - if (!isExiting) - glWindow.InputDriver.Poll(); + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + glWindow.ProcessEvents(); - - if (MustResize) - { - resizeEventArgs.Width = glWindow.Width; - resizeEventArgs.Height = glWindow.Height; - OnResizeInternal(resizeEventArgs); - } } #endregion - #region OnRenderFrame(RenderFrameEventArgs e) - - /// - /// Raises the RenderFrame event, and calls the public function. - /// - /// - private void OnRenderFrameInternal(RenderFrameEventArgs e) - { - if (RenderFrame != null) - RenderFrame(this, e); - - // Call the user's override. - OnRenderFrame(e); - } + #region OnRenderFrame /// /// Override in derived classes to render a frame. @@ -688,37 +807,18 @@ namespace OpenTK /// /// The base implementation (base.OnRenderFrame) is empty, there is no need to call it. /// - public virtual void OnRenderFrame(RenderFrameEventArgs e) + protected virtual void OnRenderFrame(FrameEventArgs e) { - if (disposed) throw new ObjectDisposedException("GameWindow"); } /// - /// Occurs when it is time to render the next frame. + /// Occurs when it is time to render a frame. /// - public event RenderFrameEvent RenderFrame; + public event EventHandler RenderFrame; #endregion - #region OnUpdateFrame(UpdateFrameEventArgs e) - - private void OnUpdateFrameInternal(UpdateFrameEventArgs e) - { - if (!this.Exists && !this.IsExiting) - { - //Debug.Print("WARNING: UpdateFrame event raised without a valid render window. This may indicate a programming error. Creating render window."); - //mode = new DisplayMode(640, 480); - //this.CreateWindow(mode); - throw new InvalidOperationException("Cannot enter game loop without a render window"); - } - - if (UpdateFrame != null) - { - UpdateFrame(this, e); - } - - OnUpdateFrame(e); - } + #region OnUpdateFrame /// /// Override in derived classes to update a frame. @@ -727,24 +827,18 @@ namespace OpenTK /// /// The base implementation (base.OnUpdateFrame) is empty, there is no need to call it. /// - public virtual void OnUpdateFrame(UpdateFrameEventArgs e) + protected virtual void OnUpdateFrame(FrameEventArgs e) { - if (disposed) throw new ObjectDisposedException("GameWindow"); } /// - /// Occurs when it is time to update the next frame. + /// Occurs when it is time to update a frame. /// - public event UpdateFrameEvent UpdateFrame; + public event EventHandler UpdateFrame; #endregion - #region OnLoad(EventArgs e) - - /// - /// Occurs after establishing an OpenGL context, but before entering the main loop. - /// - public event LoadEvent Load; + #region OnLoad /// /// Raises the Load event, and calls the user's OnLoad override. @@ -752,24 +846,14 @@ namespace OpenTK /// private void OnLoadInternal(EventArgs e) { - Debug.Print("Firing internal load event."); - if (MustResize) - { - resizeEventArgs.Width = glWindow.Width; - resizeEventArgs.Height = glWindow.Height; - OnResizeInternal(resizeEventArgs); - } - + Debug.Print("{0}.Load", this.GetType().Name); Debug.WriteLine(String.Format("OpenGL driver information: {0}, {1}, {2}", GL.GetString(StringName.Renderer), GL.GetString(StringName.Vendor), GL.GetString(StringName.Version))); - if (this.Load != null) - { - this.Load(this, e); - } - + OnResizeInternal(EventArgs.Empty); + Load(this, e); OnLoad(e); } @@ -785,12 +869,7 @@ namespace OpenTK #endregion - #region OnUnload(EventArgs e) - - /// - /// Occurs after after calling GameWindow.Exit, but before destroying the OpenGL context. - /// - public event UnloadEvent Unload; + #region OnUnload /// /// Raises the Unload event, and calls the user's OnUnload override. @@ -828,7 +907,12 @@ namespace OpenTK /// public bool IsExiting { - get { if (disposed) throw new ObjectDisposedException("GameWindow"); return isExiting; } + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + return isExiting; + } } #endregion @@ -838,12 +922,13 @@ namespace OpenTK /// /// Gets the primary Keyboard device, or null if no Keyboard exists. /// + [Obsolete] public KeyboardDevice Keyboard { get { - if (glWindow.InputDriver.Keyboard.Count > 0) - return glWindow.InputDriver.Keyboard[0]; + if (InputDriver.Keyboard.Count > 0) + return InputDriver.Keyboard[0]; else return null; } @@ -856,12 +941,13 @@ namespace OpenTK /// /// Gets the primary Mouse device, or null if no Mouse exists. /// + [Obsolete] public MouseDevice Mouse { get { - if (glWindow.InputDriver.Mouse.Count > 0) - return glWindow.InputDriver.Mouse[0]; + if (InputDriver.Mouse.Count > 0) + return InputDriver.Mouse[0]; else return null; } @@ -874,9 +960,10 @@ namespace OpenTK /// /// Gets a readonly IList containing all available OpenTK.Input.JoystickDevices. /// + [Obsolete] public IList Joysticks { - get { return glWindow.InputDriver.Joysticks; } + get { return InputDriver.Joysticks; } } #endregion @@ -890,12 +977,20 @@ namespace OpenTK { get { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) + throw new ObjectDisposedException("GameWindow"); + + GraphicsContext.Assert(); + return vsync; } set { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) + throw new ObjectDisposedException("GameWindow"); + + GraphicsContext.Assert(); + if (value == VSyncMode.Off) Context.VSync = false; else @@ -907,16 +1002,31 @@ namespace OpenTK #endregion + #region MakeCurrent + + /// + /// Makes the GraphicsContext current on the calling thread. + /// + public void MakeCurrent() + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + Context.MakeCurrent(WindowInfo); + } + + #endregion + #region public void SwapBuffers() /// /// Swaps the front and back buffer, presenting the rendered scene to the user. - /// Only useful in double- or triple-buffered formats. /// - /// Calling this function is equivalent to calling Context.SwapBuffers() public void SwapBuffers() { - if (disposed) throw new ObjectDisposedException("GameWindow"); + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + this.Context.SwapBuffers(); } @@ -962,12 +1072,427 @@ namespace OpenTK #endregion - #region --- Events --- + #region --- INativeWindow Members --- + + #region Icon /// - /// Occurs when the GameWindow is about to close. + /// Gets or sets the System.Drawing.Icon for this GameWindow. /// - public event EventHandler Closing = delegate(object sender, CancelEventArgs e) { }; + public Icon Icon + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Icon; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Icon = value; + } + } + + #endregion + + #region Focused + + /// + /// Gets a System.Boolean that indicates whether this GameWindow has input focus. + /// + public bool Focused + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Focused; + } + } + + #endregion + + #region Visible + + /// + /// Gets or sets a System.Boolean that indicates whether this GameWindow is visible. + /// + public bool Visible + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Visible; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Visible = value; + } + } + + #endregion + + #region Bounds + + /// + /// Gets or sets a structure the 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 + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Bounds; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Bounds = value; + } + } + + #endregion + + #region Location + + /// + /// Gets or sets a structure that contains the location of this window on the desktop. + /// + public Point Location + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Location; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Location = value; + } + } + + #endregion + + #region Size + + /// + /// Gets or sets a structure that contains the external size of this window. + /// + public Size Size + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Size; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Size = value; + } + } + + #endregion + + #region X + + /// + /// Gets or sets the horizontal location of this window on the desktop. + /// + public int X + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.X; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.X = value; + } + } + + #endregion + + #region Y + + /// + /// Gets or sets the vertical location of this window on the desktop. + /// + public int Y + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Y; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Y = value; + } + } + + #endregion + + #region Width + + /// + /// Gets or sets the external width of this window. + /// + public int Width + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Width; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Width = value; + } + } + + #endregion + + #region Height + + /// + /// Gets or sets the external height of this window. + /// + public int Height + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.Height; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.Height = value; + } + } + + #endregion + + #region ClientRectangle + + /// + /// 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 + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.ClientRectangle; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.ClientRectangle = value; + } + } + + #endregion + + #region ClientSize + + /// + /// Gets or sets a structure that contains the internal size this window. + /// + public Size ClientSize + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.ClientSize; + } + set + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + glWindow.ClientSize = value; + } + } + + #endregion + + #region InputDriver + + [Obsolete] + public IInputDriver InputDriver + { + get + { + if (disposed) + throw new ObjectDisposedException(this.GetType().Name); + + return glWindow.InputDriver; + } + } + + #endregion + + #region Close + + public void Close() + { + Exit(); + } + + #endregion + + #region PointToClient + + /// + /// Transforms the specified point from screen to client coordinates. + /// + /// + /// A to transform. + /// + /// + /// The point transformed to client coordinates. + /// + public System.Drawing.Point PointToClient(System.Drawing.Point point) + { + return glWindow.PointToClient(point); + } + + #endregion + + #region PointToScreen + + /// + /// Transforms the specified point from client to screen coordinates. + /// + /// + /// A to transform. + /// + /// + /// The point transformed to screen coordinates. + /// + public System.Drawing.Point PointToScreen(System.Drawing.Point p) + { + // Here we use the fact that PointToClient just translates the point, and PointToScreen + // should perform the inverse operation. + System.Drawing.Point trans = PointToClient(System.Drawing.Point.Empty); + p.X -= trans.X; + p.Y -= trans.Y; + return p; + } + + #endregion + + #region Events + + /// + /// Occurs before the window is displayed for the first time. + /// + public event EventHandler Load = delegate { }; + + /// + /// Occurs before the window is destroyed. + /// + public event EventHandler Unload = delegate { }; + + /// + /// Occurs whenever the window is moved. + /// + public event EventHandler Move = delegate { }; + + /// + /// Occurs whenever the window is resized. + /// + public event EventHandler Resize = delegate { }; + + /// + /// Occurs when the window is about to close. + /// + public event EventHandler Closing = delegate { }; + + /// + /// Occurs after the window has closed. + /// + public event EventHandler Closed = delegate { }; + + /// + /// Occurs when the window is disposed. + /// + public event EventHandler Disposed = delegate { }; + + /// + /// Occurs when the property of the window changes. + /// + public event EventHandler IconChanged = delegate { }; + + /// + /// Occurs when the property of the window changes. + /// + public event EventHandler TitleChanged = delegate { }; + + /// + /// Occurs when the property of the window changes. + /// + public event EventHandler VisibleChanged = delegate { }; + + /// + /// Occurs when the property of the window changes. + /// + public event EventHandler FocusedChanged = delegate { }; + + #endregion #endregion @@ -1216,173 +1741,6 @@ namespace OpenTK #endregion - #region --- IResizable Members --- - - #region public int Width, Height - - /// - /// Gets or sets the Width of the GameWindow's rendering area, in pixels. - /// - public int Width - { - get { if (disposed) throw new ObjectDisposedException("GameWindow"); return width; } - set - { - if (disposed) throw new ObjectDisposedException("GameWindow"); - if (value == this.Width) - { - return; - } - else if (value > 0) - { - glWindow.Width = value; - } - else - { - throw new ArgumentOutOfRangeException( - "Width", - value, - "Width must be greater than 0" - ); - } - } - } - - /// - /// Gets or sets the Height of the GameWindow's rendering area, in pixels. - /// - public int Height - { - get { if (disposed) throw new ObjectDisposedException("GameWindow"); return height; } - set - { - if (disposed) throw new ObjectDisposedException("GameWindow"); - if (value == this.Height) - { - return; - } - else if (value > 0) - { - glWindow.Height = value; - } - else - { - throw new ArgumentOutOfRangeException( - "Height", - value, - "Height must be greater than 0" - ); - } - } - } - - #endregion - - #region public event ResizeEvent Resize; - - /// - /// Occurs when the GameWindow is resized. Derived classes should override the OnResize method for better performance. - /// - public event ResizeEvent Resize; - - /// - /// Raises the Resize event. - /// - /// Contains information about the Resize event. - private void OnResizeInternal(ResizeEventArgs e) - { - Debug.Print("Firing internal resize event: {0}.", e.ToString()); - - this.width = e.Width; - this.height = e.Height; - - if (this.Resize != null) - this.Resize(this, e); - - OnResize(e); - } - - /// - /// Override in derived classes to respond to the Resize events. - /// - /// Contains information about the Resize event. - protected virtual void OnResize(ResizeEventArgs e) - { - if (disposed) throw new ObjectDisposedException("GameWindow"); - } - - #endregion - - /* - /// - /// Gets the Top coordinate of the GameWindow's rendering area, in pixel coordinates relative to the GameWindow's top left point. - /// - public int Top - { - get { return glWindow.Top; } - } - - /// - /// /// Gets the Bottom coordinate of the GameWindow's rendering area, in pixel coordinates relative to the GameWindow's top left point. - /// - public int Bottom - { - get { return glWindow.Bottom; } - } - - /// - /// Gets the Left coordinate of the GameWindow's rendering area, in pixel coordinates relative to the GameWindow's top left point. - /// - public int Left - { - get { return glWindow.Left; } - } - - /// - /// Gets the Right coordinate of the GameWindow's rendering area, in pixel coordinates relative to the GameWindow's top left point. - /// - public int Right - { - get { return glWindow.Right; } - } - */ - #endregion - - #region PointToClient - - /// - /// Converts the screen coordinates of a specified point on the screen to client-area coordinates. - /// - /// A System.Drawing.Point structure that specifies the screen coordinates to be converted - /// The client-area coordinates of the point. The new coordinates are relative to the upper-left corner of the GameWindow's client area. - public System.Drawing.Point PointToClient(System.Drawing.Point point) - { - point = glWindow.PointToClient(point); - - return point; - } - - #endregion - - #region PointToScreen - - /// - /// Converts the client-area coordinates of a specified point to screen coordinates. - /// - /// A System.Drawing.Point structure that specifies the client-area coordinates to be converted - /// The screen coordinates of the point, relative to the upper-left corner of the screen. Note, a screen-coordinate point that is above the window's client area has a negative y-coordinate. Similarly, a screen coordinate to the left of a client area has a negative x-coordinate. - public System.Drawing.Point PointToScreen(System.Drawing.Point p) - { - // Here we use the fact that PointToClient just translates the point, and PointToScreen - // should perform the inverse operation. - System.Drawing.Point trans = PointToClient(System.Drawing.Point.Empty); - p.X -= trans.X; - p.Y -= trans.Y; - return p; - } - - #endregion - #region --- IDisposable Members --- /// diff --git a/Source/OpenTK/Graphics/DisplayDevice.cs b/Source/OpenTK/Graphics/DisplayDevice.cs index 660281b9..d69bb1f0 100644 --- a/Source/OpenTK/Graphics/DisplayDevice.cs +++ b/Source/OpenTK/Graphics/DisplayDevice.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Threading; -using System.Windows.Forms; +using System.Drawing; namespace OpenTK.Graphics { @@ -27,6 +27,8 @@ namespace OpenTK.Graphics // TODO: Does not detect changes to primary device. // TODO: Mono does not support System.Windows.Forms.Screen.BitsPerPixel -- find workaround! + #region --- Fields --- + DisplayResolution current_resolution, original_resolution; List available_resolutions = new List(); bool primary; @@ -38,23 +40,13 @@ namespace OpenTK.Graphics static IDisplayDeviceDriver implementation; + #endregion + #region --- Constructors --- static DisplayDevice() { - implementation = Platform.Factory.CreateDisplayDeviceDriver(); - - //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; - // } - //} + implementation = Platform.Factory.Default.CreateDisplayDeviceDriver(); } internal DisplayDevice(DisplayResolution currentResolution, bool primary, @@ -79,6 +71,18 @@ namespace OpenTK.Graphics #region --- Public Methods --- + #region public Rectangle Bounds + + /// + /// Gets a System.Drawing.Rectangle that contains the current bounds of this DisplayDevice. + /// + public Rectangle Bounds + { + get { return current_resolution.Bounds; } + } + + #endregion + #region public int Width /// Gets a System.Int32 that contains the width of this display in pixels. diff --git a/Source/OpenTK/Graphics/DisplayResolution.cs b/Source/OpenTK/Graphics/DisplayResolution.cs index 68c95462..2c9cbec7 100644 --- a/Source/OpenTK/Graphics/DisplayResolution.cs +++ b/Source/OpenTK/Graphics/DisplayResolution.cs @@ -10,13 +10,14 @@ using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; +using System.Drawing; namespace OpenTK.Graphics { /// Contains information regarding a monitor's display resolution. public class DisplayResolution { - int width, height; + Rectangle bounds; int bits_per_pixel; float refresh_rate; @@ -32,7 +33,7 @@ namespace OpenTK.Graphics /// The requested bits per pixel in bits. /// The requested refresh rate in Herz. /// OpenTK will select the closest match between all available resolutions on the primary DisplayDevice. - internal DisplayResolution(int width, int height, int bitsPerPixel, float refreshRate) + internal DisplayResolution(int x, int y, int width, int height, int bitsPerPixel, float refreshRate) { // Refresh rate may be zero, since this information may not be available on some platforms. if (width <= 0) throw new ArgumentOutOfRangeException("width", "Must be greater than zero."); @@ -40,8 +41,7 @@ namespace OpenTK.Graphics if (bitsPerPixel <= 0) throw new ArgumentOutOfRangeException("bitsPerPixel", "Must be greater than zero."); if (refreshRate < 0) throw new ArgumentOutOfRangeException("refreshRate", "Must be greater than, or equal to zero."); - this.width = width; - this.height = height; + this.bounds = new Rectangle(x, y, width, height); this.bits_per_pixel = bitsPerPixel; this.refresh_rate = refreshRate; } @@ -84,17 +84,29 @@ namespace OpenTK.Graphics #region --- Public Methods --- + #region Bounds + + /// + /// Gets a System.Drawing.Rectangle that contains the bounds of this display device. + /// + public Rectangle Bounds + { + get { return bounds; } + } + + #endregion + #region public int Width /// Gets a System.Int32 that contains the width of this display in pixels. - public int Width { get { return width; } } + public int Width { get { return bounds.Width; } } #endregion #region public int Height /// Gets a System.Int32 that contains the height of this display in pixels. - public int Height { get { return height; } } + public int Height { get { return bounds.Height; } } #endregion @@ -129,7 +141,7 @@ namespace OpenTK.Graphics /// A System.String representing this DisplayResolution. public override string ToString() { - return String.Format("{0}x{1}x{2}@{3}Hz", width, height, bits_per_pixel, refresh_rate); + return String.Format("{0}x{1}@{2}Hz", Bounds, bits_per_pixel, refresh_rate); } #endregion @@ -163,7 +175,7 @@ namespace OpenTK.Graphics /// A System.Int32 that may serve as a hash code for this resolution. public override int GetHashCode() { - return width ^ height ^ bits_per_pixel ^ (int)refresh_rate; + return Bounds.GetHashCode() ^ bits_per_pixel ^ refresh_rate.GetHashCode(); } #endregion diff --git a/Source/OpenTK/Graphics/GraphicsContext.cs b/Source/OpenTK/Graphics/GraphicsContext.cs index d63bc0d6..91668019 100644 --- a/Source/OpenTK/Graphics/GraphicsContext.cs +++ b/Source/OpenTK/Graphics/GraphicsContext.cs @@ -43,7 +43,7 @@ namespace OpenTK.Graphics static GraphicsContext() { - GetCurrentContext = Factory.CreateGetCurrentGraphicsContext(); + GetCurrentContext = Factory.Default.CreateGetCurrentGraphicsContext(); } // Necessary to allow creation of dummy GraphicsContexts (see CreateDummyContext static method). @@ -116,7 +116,7 @@ namespace OpenTK.Graphics if (designMode) implementation = new Platform.Dummy.DummyGLContext(); else - implementation = Factory.CreateGLContext(mode, window, shareContext, DirectRendering, major, minor, flags); + implementation = Factory.Default.CreateGLContext(mode, window, shareContext, DirectRendering, major, minor, flags); lock (context_lock) { @@ -378,13 +378,13 @@ namespace OpenTK.Graphics /// /// Makes the GraphicsContext the current rendering target. /// - /// A System.Platform.IWindowInfo structure for the window this context is bound to. + /// A valid structure. /// /// You can use this method to bind the GraphicsContext to a different window than the one it was created from. /// - public void MakeCurrent(IWindowInfo info) + public void MakeCurrent(IWindowInfo window) { - implementation.MakeCurrent(info); + implementation.MakeCurrent(window); } /// diff --git a/Source/OpenTK/Graphics/GraphicsMode.cs b/Source/OpenTK/Graphics/GraphicsMode.cs index b70aaa0f..b4a7ed27 100644 --- a/Source/OpenTK/Graphics/GraphicsMode.cs +++ b/Source/OpenTK/Graphics/GraphicsMode.cs @@ -31,7 +31,7 @@ namespace OpenTK.Graphics static GraphicsMode() { - implementation = Platform.Factory.CreateGraphicsMode(); + implementation = Platform.Factory.Default.CreateGraphicsMode(); } #endregion diff --git a/Source/OpenTK/IGameWindow.cs b/Source/OpenTK/IGameWindow.cs new file mode 100644 index 00000000..489fd703 --- /dev/null +++ b/Source/OpenTK/IGameWindow.cs @@ -0,0 +1,85 @@ +#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.Collections.Generic; +using System.Text; + +namespace OpenTK.Platform +{ + /// + /// Defines the interface for a GameWindow. + /// + interface IGameWindow : INativeWindow + { + /// + /// Enters the game loop of the GameWindow using the maximum update rate. + /// + /// + void Run(); + + /// + /// Enters the game loop of the GameWindow using the specified update rate. + /// + void Run(double updateRate); + + /// + /// Makes the GraphicsContext current on the calling thread. + /// + void MakeCurrent(); + + /// + /// Swaps the front and back buffers of the current GraphicsContext, presenting the rendered scene to the user. + /// + void SwapBuffers(); + + /// + /// Occurs before the window is displayed for the first time. + /// + event EventHandler Load; + + /// + /// Occurs before the window is destroyed. + /// + event EventHandler Unload; + + /// + /// Occurs when it is time to update a frame. + /// + event EventHandler UpdateFrame; + + /// + /// Occurs when it is time to render a frame. + /// + event EventHandler RenderFrame; + } + + [Obsolete] public delegate void UpdateFrameEvent(GameWindow sender, UpdateFrameEventArgs e); + [Obsolete] public delegate void RenderFrameEvent(GameWindow sender, RenderFrameEventArgs e); + [Obsolete] public delegate void LoadEvent(GameWindow sender, EventArgs e); + [Obsolete] public delegate void UnloadEvent(GameWindow sender, EventArgs e); +} diff --git a/Source/OpenTK/INativeWindow.cs b/Source/OpenTK/INativeWindow.cs new file mode 100644 index 00000000..083a624d --- /dev/null +++ b/Source/OpenTK/INativeWindow.cs @@ -0,0 +1,226 @@ +#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.Collections.Generic; +using System.Text; +using System.Drawing; +using OpenTK.Platform; +using System.ComponentModel; + +namespace OpenTK +{ + /// + /// Defines the interface for a native window. + /// + public interface INativeWindow : IDisposable + { + /// + /// Gets or sets the of the window. + /// + Icon Icon { get; set; } + + /// + /// Gets or sets the title of the window. + /// + string Title { get; set; } + + /// + /// Gets a System.Boolean that indicates whether this window has input focus. + /// + bool Focused { get; } + + /// + /// Gets or sets a System.Boolean that indicates whether the window is visible. + /// + bool Visible { get; set; } + + /// + /// Gets a System.Boolean that indicates whether the window has been created and has not been destroyed. + /// + bool Exists { get; } + + /// + /// Gets the for this window. + /// + IWindowInfo WindowInfo { get; } + + /// + /// Gets or sets the for this window. + /// + WindowState WindowState { get; set; } + + /// + /// Gets or sets the for this window. + /// + WindowBorder WindowBorder { get; set; } + + /// + /// Gets or sets a structure the contains the external bounds of this window, in screen coordinates. + /// External bounds include the title bar, borders and drawing area of the window. + /// + Rectangle Bounds { get; set; } + + /// + /// Gets or sets a structure that contains the location of this window on the desktop. + /// + Point Location { get; set; } + + /// + /// Gets or sets a structure that contains the external size of this window. + /// + Size Size { get; set; } + + /// + /// Gets or sets the horizontal location of this window on the desktop. + /// + int X { get; set; } + + /// + /// Gets or sets the vertical location of this window on the desktop. + /// + int Y { get; set; } + + /// + /// Gets or sets the external width of this window. + /// + int Width { get; set; } + + /// + /// Gets or sets the external height of this window. + /// + int Height { get; set; } + + /// + /// 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. + /// + Rectangle ClientRectangle { get; set; } + + /// + /// Gets or sets a structure that contains the internal size this window. + /// + Size ClientSize { get; set; } + + [Obsolete] + OpenTK.Input.IInputDriver InputDriver { get; } + + /// + /// Closes this window. Equivalent to . + /// + void Close(); + + /// + /// Processes pending window events. + /// + void ProcessEvents(); + + /// + /// Transforms the specified point from screen to client coordinates. + /// + /// + /// A to transform. + /// + /// + /// The point transformed to client coordinates. + /// + Point PointToClient(Point point); + + /// + /// Transforms the specified point from client to screen coordinates. + /// + /// + /// A to transform. + /// + /// + /// The point transformed to screen coordinates. + /// + Point PointToScreen(Point point); + + /// + /// Occurs whenever the window is moved. + /// + event EventHandler Move; + + /// + /// Occurs whenever the window is resized. + /// + event EventHandler Resize; + + /// + /// Occurs when the window is about to close. + /// + event EventHandler Closing; + + /// + /// Occurs after the window has closed. + /// + event EventHandler Closed; + + /// + /// Occurs when the window is disposed. + /// + event EventHandler Disposed; + + /// + /// Occurs when the property of the window changes. + /// + event EventHandler IconChanged; + + /// + /// Occurs when the property of the window changes. + /// + event EventHandler TitleChanged; + + /// + /// Occurs when the property of the window changes. + /// + event EventHandler VisibleChanged; + + /// + /// Occurs when the property of the window changes. + /// + event EventHandler FocusedChanged; + + //event EventHandler MouseEnter; + //event EventHandler MouseMove; + //event EventHandler MouseWheel; + //event EventHandler MouseDown; + //event EventHandler MouseUp; + //event EventHandler MouseClick; + //event EventHandler MouseDoubleClick; + + //event EventHandler KeyDown; + //event EventHandler KeyUp; + //event EventHandler KeyPress; + + //event EventHandler DragDrop; + //event EventHandler DragEnter; + //event EventHandler DragOver; + //event EventHandler DragLeave; + } +} diff --git a/Source/OpenTK/Input/KeyboardDevice.cs b/Source/OpenTK/Input/KeyboardDevice.cs index 05dbd270..a7e1a7b0 100644 --- a/Source/OpenTK/Input/KeyboardDevice.cs +++ b/Source/OpenTK/Input/KeyboardDevice.cs @@ -203,8 +203,10 @@ namespace OpenTK.Input /// public enum Key : int { + None = 0, + // Modifiers - ShiftLeft = 0, + ShiftLeft, ShiftRight, ControlLeft, ControlRight, diff --git a/Source/OpenTK/Platform/Factory.cs b/Source/OpenTK/Platform/Factory.cs index 1b7f1cdb..9af6a1c5 100644 --- a/Source/OpenTK/Platform/Factory.cs +++ b/Source/OpenTK/Platform/Factory.cs @@ -1,3 +1,30 @@ +#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.Collections.Generic; using System.Text; @@ -6,10 +33,16 @@ namespace OpenTK.Platform { using Graphics; - static class Factory + class Factory : IPlatformFactory { + #region Fields + static IPlatformFactory implementation; + #endregion + + #region Constructors + static Factory() { if (Configuration.RunningOnWindows) implementation = new Windows.WinFactory(); @@ -18,32 +51,46 @@ namespace OpenTK.Platform else implementation = new UnsupportedPlatform(); } - internal static INativeGLWindow CreateNativeGLWindow() + #endregion + + #region Public Members + + public static IPlatformFactory Default { - return implementation.CreateGLNative(); + get { return implementation; } } - internal static IGLControl CreateGLControl(GraphicsMode mode, GLControl owner) + #endregion + + #region IPlatformFactory Members + + public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, + GraphicsMode mode, GameWindowFlags options, DisplayDevice device) + { + return implementation.CreateNativeWindow(x, y, width, height, title, mode, options, device); + } + + public IGLControl CreateGLControl(GraphicsMode mode, GLControl owner) { return implementation.CreateGLControl(mode, owner); } - internal static IDisplayDeviceDriver CreateDisplayDeviceDriver() + public IDisplayDeviceDriver CreateDisplayDeviceDriver() { return implementation.CreateDisplayDeviceDriver(); } - internal static IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) + public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) { return implementation.CreateGLContext(mode, window, shareContext, directRendering, major, minor, flags); } - internal static GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() + public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() { return implementation.CreateGetCurrentGraphicsContext(); } - - internal static IGraphicsMode CreateGraphicsMode() + + public IGraphicsMode CreateGraphicsMode() { return implementation.CreateGraphicsMode(); } @@ -57,6 +104,11 @@ namespace OpenTK.Platform throw new PlatformNotSupportedException("Please, refer to http://www.opentk.com for more information."); } + public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) + { + throw new PlatformNotSupportedException("Please, refer to http://www.opentk.com for more information."); + } + public IGLControl CreateGLControl(GraphicsMode mode, GLControl owner) { throw new PlatformNotSupportedException("Please, refer to http://www.opentk.com for more information."); @@ -85,5 +137,7 @@ namespace OpenTK.Platform #endregion } + + #endregion } } diff --git a/Source/OpenTK/Platform/IGameWindow.cs b/Source/OpenTK/Platform/IGameWindow.cs deleted file mode 100644 index 220c4b25..00000000 --- a/Source/OpenTK/Platform/IGameWindow.cs +++ /dev/null @@ -1,41 +0,0 @@ -#region --- License --- -/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos - * See license.txt for license info - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenTK.Platform -{ - interface IGameWindow : INativeGLWindow - { - void Run(); - - void OnRenderFrame(RenderFrameEventArgs e); - void OnUpdateFrame(UpdateFrameEventArgs e); - void OnLoad(EventArgs e); - void Exit(); - - void SwapBuffers(); - - event UpdateFrameEvent UpdateFrame; - event RenderFrameEvent RenderFrame; - event LoadEvent Load; - event UnloadEvent Unload; - - bool IsExiting { get; } - //IList Keyboard { get; } - //IList Mouse { get; } - - OpenTK.Input.KeyboardDevice Keyboard { get; } - OpenTK.Input.MouseDevice Mouse { get; } - } - - public delegate void UpdateFrameEvent(GameWindow sender, UpdateFrameEventArgs e); - public delegate void RenderFrameEvent(GameWindow sender, RenderFrameEventArgs e); - public delegate void LoadEvent(GameWindow sender, EventArgs e); - public delegate void UnloadEvent(GameWindow sender, EventArgs e); -} diff --git a/Source/OpenTK/Platform/INativeGLWindow.cs b/Source/OpenTK/Platform/INativeGLWindow.cs index fee7bff4..dcd95c4c 100644 --- a/Source/OpenTK/Platform/INativeGLWindow.cs +++ b/Source/OpenTK/Platform/INativeGLWindow.cs @@ -16,8 +16,9 @@ using System.Drawing; namespace OpenTK.Platform { - internal interface INativeGLWindow : IResizable, IDisposable + internal interface INativeGLWindow : IDisposable { + [Obsolete] void CreateWindow(int width, int height, GraphicsMode mode, int major, int minor, GraphicsContextFlags flags, out IGraphicsContext context); void DestroyWindow(); void ProcessEvents(); diff --git a/Source/OpenTK/Platform/IPlatformFactory.cs b/Source/OpenTK/Platform/IPlatformFactory.cs index e8ac1edd..f1918219 100644 --- a/Source/OpenTK/Platform/IPlatformFactory.cs +++ b/Source/OpenTK/Platform/IPlatformFactory.cs @@ -1,18 +1,47 @@ +#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.Collections.Generic; using System.Text; +using OpenTK.Graphics; + namespace OpenTK.Platform { interface IPlatformFactory { - INativeGLWindow CreateGLNative(); + INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device); - IGLControl CreateGLControl(OpenTK.Graphics.GraphicsMode mode, GLControl owner); + IGLControl CreateGLControl(GraphicsMode mode, GLControl owner); - OpenTK.Graphics.IDisplayDeviceDriver CreateDisplayDeviceDriver(); + IDisplayDeviceDriver CreateDisplayDeviceDriver(); - OpenTK.Graphics.IGraphicsContext CreateGLContext(OpenTK.Graphics.GraphicsMode mode, IWindowInfo window, OpenTK.Graphics.IGraphicsContext shareContext, bool DirectRendering, int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags); + IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool DirectRendering, int major, int minor, GraphicsContextFlags flags); OpenTK.Graphics.GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext(); diff --git a/Source/OpenTK/Platform/MacOS/Application.cs b/Source/OpenTK/Platform/MacOS/Application.cs index d905902b..0f9923e3 100644 --- a/Source/OpenTK/Platform/MacOS/Application.cs +++ b/Source/OpenTK/Platform/MacOS/Application.cs @@ -115,7 +115,7 @@ namespace OpenTK.Platform.MacOS.Carbon public static void Run(CarbonGLNative window) { window.Destroy += MainWindowClosed; - window.Show(); + window.Visible = true; API.RunApplicationEventLoop(); diff --git a/Source/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs b/Source/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs index dcae0503..b2b0b8b9 100644 --- a/Source/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs +++ b/Source/OpenTK/Platform/MacOS/CarbonBindings/CarbonAPI.cs @@ -81,6 +81,11 @@ namespace OpenTK.Platform.MacOS.Carbon return string.Format( "Rect: [{0}, {1}, {2}, {3}]", X, Y, Width, Height); } + + public System.Drawing.Rectangle ToRectangle() + { + return new System.Drawing.Rectangle(X, Y, Width, Height); + } } #endregion @@ -444,6 +449,8 @@ namespace OpenTK.Platform.MacOS.Carbon internal static extern OSStatus RepositionWindow(IntPtr window, IntPtr parentWindow, WindowPositionMethod method); [DllImport(carbon)] internal static extern void SizeWindow(IntPtr window, short w, short h, bool fUpdate); + [DllImport(carbon)] + internal static extern void MoveWindow(IntPtr window, short x, short y, bool fUpdate); [DllImport(carbon)] static extern OSStatus GetWindowBounds(IntPtr window, WindowRegionCode regionCode, out Rect globalBounds); diff --git a/Source/OpenTK/Platform/MacOS/CarbonGLNative.cs b/Source/OpenTK/Platform/MacOS/CarbonGLNative.cs index 9d418c47..a0e608cd 100644 --- a/Source/OpenTK/Platform/MacOS/CarbonGLNative.cs +++ b/Source/OpenTK/Platform/MacOS/CarbonGLNative.cs @@ -1,11 +1,29 @@ +#region License // -// -// xCSCarbon +// The Open Toolkit Library License // -// Created by Erik Ylvisaker on 3/17/08. -// Copyright 2008 __MyCompanyName__. All rights reserved. +// 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.Collections.Generic; @@ -18,8 +36,10 @@ namespace OpenTK.Platform.MacOS using Carbon; using Graphics; - class CarbonGLNative : INativeGLWindow + class CarbonGLNative : INativeGLWindow, INativeWindow { + #region Fields + CarbonWindowInfo window; CarbonInput mInputDriver; GraphicsContext context; @@ -29,8 +49,7 @@ namespace OpenTK.Platform.MacOS IntPtr uppHandler; string title = "OpenTK Window"; - short mWidth, mHeight; - short mWindowedWidth, mWindowedHeight; + System.Drawing.Rectangle bounds, windowedBounds, clientRectangle; bool mIsDisposed = false; WindowAttributes mWindowAttrib; @@ -42,36 +61,48 @@ namespace OpenTK.Platform.MacOS static Dictionary mWindows = new Dictionary(); + #endregion + + #region Constructors + static CarbonGLNative() { Application.Initialize(); } - public CarbonGLNative() + + CarbonGLNative() : this(WindowClass.Document, WindowAttributes.StandardDocument | WindowAttributes.StandardHandler | WindowAttributes.InWindowMenu | WindowAttributes.LiveResize) - { + { } - } - private CarbonGLNative(WindowClass @class, WindowAttributes attrib) + + CarbonGLNative(WindowClass @class, WindowAttributes attrib) { mWindowClass = @class; mWindowAttrib = attrib; - - } - ~CarbonGLNative() + + public CarbonGLNative(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) { - Dispose(false); + CreateNativeWindow(WindowClass.Document, + WindowAttributes.StandardDocument | WindowAttributes.StandardHandler | + WindowAttributes.InWindowMenu | WindowAttributes.LiveResize, + new Rect((short)x, (short)y, (short)width, (short)height)); } + #endregion + + #region IDisposable + public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + protected virtual void Dispose(bool disposing) { if (mIsDisposed) @@ -92,19 +123,26 @@ namespace OpenTK.Platform.MacOS DisposeUPP(); } - private void DisposeUPP() + ~CarbonGLNative() + { + Dispose(false); + } + + #endregion + + #region Private Members + + void DisposeUPP() { if (uppHandler != IntPtr.Zero) { //API.RemoveEventHandler(uppHandler); //API.DisposeEventHandlerUPP(uppHandler); - } uppHandler = IntPtr.Zero; } - void CreateNativeWindow(WindowClass @class, WindowAttributes attrib, Rect r) { Debug.Print("Creating window..."); @@ -115,6 +153,7 @@ namespace OpenTK.Platform.MacOS window = new CarbonWindowInfo(windowRef, true, false); + SetLocation(r.X, r.Y); SetSize(r.Width, r.Height); Debug.Unindent(); @@ -133,6 +172,7 @@ namespace OpenTK.Platform.MacOS System.Diagnostics.Debug.Print("Attached window events."); } + void ConnectEvents() { mInputDriver = new CarbonInput(); @@ -165,25 +205,12 @@ namespace OpenTK.Platform.MacOS Application.WindowEventHandler = this; } - - public string Title - { - get - { - return title; - } - set - { - API.SetWindowTitle(window.WindowRef, value); - title = value; - } - } - - public void Activate() + void Activate() { API.SelectWindow(window.WindowRef); } - public void Show() + + void Show() { IntPtr parent = IntPtr.Zero; @@ -191,27 +218,37 @@ namespace OpenTK.Platform.MacOS API.RepositionWindow(window.WindowRef, parent, WindowPositionMethod); API.SelectWindow(window.WindowRef); } - public void Hide() + + void Hide() { API.HideWindow(window.WindowRef); } - public bool Visible + + void SetFullscreen() { - get { return API.IsWindowVisible(window.WindowRef); } - set - { - if (value && Visible == false) - Show(); - else - Hide(); - } + windowedBounds = bounds; + + ((AglContext)(context as IGraphicsContextInternal).Implementation).SetFullScreen(window); + + Debug.Print("Prev Size: {0}, {1}", Width, Height); + + bounds = DisplayDevice.Default.Bounds; + + Debug.Print("New Size: {0}, {1}", Width, Height); } - public bool IsDisposed + + void UnsetFullscreen() + { + ((AglContext)(context as IGraphicsContextInternal).Implementation).UnsetFullScreen(window); + SetSize((short)windowedBounds.Width, (short)windowedBounds.Height); + } + + bool IsDisposed { get { return mIsDisposed; } } - public WindowPositionMethod WindowPositionMethod + WindowPositionMethod WindowPositionMethod { get { return mPositionMethod; } set { mPositionMethod = value; } @@ -276,7 +313,6 @@ namespace OpenTK.Platform.MacOS default: return OSStatus.EventNotHandled; } - } private OSStatus ProcessKeyboardEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) @@ -321,7 +357,7 @@ namespace OpenTK.Platform.MacOS { case WindowEventKind.WindowClose: CancelEventArgs cancel = new CancelEventArgs(); - OnQueryWindowClose(cancel); + OnClosing(cancel); if (cancel.Cancel) return OSStatus.NoError; @@ -329,7 +365,7 @@ namespace OpenTK.Platform.MacOS return OSStatus.EventNotHandled; case WindowEventKind.WindowClosed: - OnWindowClosed(); + OnClosed(); return OSStatus.NoError; @@ -356,7 +392,7 @@ namespace OpenTK.Platform.MacOS MouseButton button = MouseButton.Primary; HIPoint pt = new HIPoint(); - OSStatus err ; + OSStatus err; if (this.windowState == WindowState.Fullscreen) { @@ -498,31 +534,29 @@ namespace OpenTK.Platform.MacOS return retval; } - public int Width + void SetLocation(short x, short y) { - get { return mWidth; } - set { SetSize(value, mHeight); } + if (windowState == WindowState.Fullscreen) + return; + + API.MoveWindow(window.WindowRef, x, y, false); } - public int Height - { - get { return mHeight; } - set { SetSize(mWidth, value); } - } - public void SetSize(int width, int height) + + void SetSize(short width, short height) { if (WindowState == WindowState.Fullscreen) return; - mWidth = (short)width; - mHeight = (short)height; - - API.SizeWindow(window.WindowRef, mWidth, mHeight, true); + // Todo: why call SizeWindow twice? + API.SizeWindow(window.WindowRef, width, height, true); + bounds.Width = (short)width; + bounds.Height = (short)height; Rect contentBounds = API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion); Rect newSize = new Rect(0, 0, - (short)(2 * mWidth - contentBounds.Width), - (short)(2 * mHeight - contentBounds.Height)); + (short)(2 * width - contentBounds.Width), + (short)(2 * height - contentBounds.Height)); Debug.Print("Content region was: {0}", contentBounds); Debug.Print("Resizing window to: {0}", newSize); @@ -531,6 +565,7 @@ namespace OpenTK.Platform.MacOS contentBounds = API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion); Debug.Print("New content region size: {0}", contentBounds); + clientRectangle = contentBounds.ToRectangle(); } protected void OnResize() @@ -551,26 +586,22 @@ namespace OpenTK.Platform.MacOS if (WindowState == WindowState.Fullscreen) return; - Rect region = GetRegion(); - - mWidth = (short)(region.Width); - mHeight = (short)(region.Height); + bounds = GetRegion().ToRectangle(); } - protected virtual void OnQueryWindowClose(CancelEventArgs e) + protected virtual void OnClosing(CancelEventArgs e) { - if (QueryWindowClose != null) - QueryWindowClose(this, e); + if (Closing != null) + Closing(this, e); } - protected virtual void OnWindowClosed() + + protected virtual void OnClosed() { - if (Destroy != null) - Destroy(this, EventArgs.Empty); - + if (Closed != null) + Closed(this, EventArgs.Empty); } - public event CancelEventHandler QueryWindowClose; - + #endregion #region INativeGLWindow Members @@ -650,12 +681,6 @@ namespace OpenTK.Platform.MacOS #endregion - #region IResizable Members - - public event ResizeEvent Resize; - - #endregion - #region INativeGLWindow Members public WindowState WindowState @@ -728,28 +753,6 @@ namespace OpenTK.Platform.MacOS } } - - private void SetFullscreen() - { - ((AglContext)(context as IGraphicsContextInternal).Implementation).SetFullScreen(window); - - mWindowedWidth = mWidth; - mWindowedHeight = mHeight; - - Debug.Print("Prev Size: {0}, {1}", Width, Height); - - mWidth = (short)DisplayDevice.Default.Width; - mHeight = (short)DisplayDevice.Default.Height; - - Debug.Print("New Size: {0}, {1}", Width, Height); - - } - private void UnsetFullscreen() - { - ((AglContext)(context as IGraphicsContextInternal).Implementation).UnsetFullScreen(window); - SetSize(mWindowedWidth, mWindowedHeight); - } - public WindowBorder WindowBorder { get @@ -775,5 +778,180 @@ namespace OpenTK.Platform.MacOS #endregion + #region INativeWindow Members + + public string Title + { + get + { + return title; + } + set + { + API.SetWindowTitle(window.WindowRef, value); + title = value; + } + } + + public bool Visible + { + get { return API.IsWindowVisible(window.WindowRef); } + set + { + if (value && Visible == false) + Show(); + else + Hide(); + } + } + + public System.Drawing.Icon Icon + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + public bool Focused + { + get { throw new NotImplementedException(); } + } + + public System.Drawing.Rectangle Bounds + { + get + { + return bounds; + } + set + { + Location = value.Location; + Size = value.Size; + } + } + + public System.Drawing.Point Location + { + get + { + return bounds.Location; + } + set + { + SetLocation((short)value.X, (short)value.Y); + } + } + + public System.Drawing.Size Size + { + get + { + return bounds.Size; + } + set + { + SetSize((short)value.Width, (short)value.Height); + } + } + + public int Width + { + get { return Bounds.Width; } + set { Size = new System.Drawing.Size(value, Height); } + } + + public int Height + { + get { return Bounds.Height; } + set { Size = new System.Drawing.Size(Width, value); } + } + + public int X + { + get + { + return bounds.X; + } + set + { + Location = new System.Drawing.Point(value, Y); + } + } + + public int Y + { + get + { + return bounds.Y; + } + set + { + Location = new System.Drawing.Point(X, value); + } + } + + public System.Drawing.Rectangle ClientRectangle + { + get + { + return clientRectangle; + } + set + { + throw new NotImplementedException(); + } + } + + public System.Drawing.Size ClientSize + { + get + { + return clientRectangle.Size; + } + set + { + throw new NotImplementedException(); + } + } + + public void Close() + { + throw new NotImplementedException(); + } + + public event EventHandler Idle; + + public event EventHandler Load; + + public event EventHandler Unload; + + public event EventHandler Move; + + public event EventHandler Resize; + + public event EventHandler Closing; + + public event EventHandler Closed; + + public event EventHandler Disposed; + + public event EventHandler IconChanged; + + public event EventHandler TitleChanged; + + public event EventHandler ClientSizeChanged; + + public event EventHandler VisibleChanged; + + public event EventHandler WindowInfoChanged; + + public event EventHandler FocusedChanged; + + #endregion } } diff --git a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs index f55cdaf1..0447a1ce 100644 --- a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs +++ b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs @@ -1,3 +1,30 @@ +#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.Collections.Generic; using System.Text; @@ -12,7 +39,12 @@ namespace OpenTK.Platform.MacOS public INativeGLWindow CreateGLNative() { - return new CarbonGLNative(); + throw new NotImplementedException(); + } + + public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) + { + return new CarbonGLNative(x, y, width, height, title, mode, options, device); } public IGLControl CreateGLControl(GraphicsMode mode, GLControl owner) diff --git a/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs b/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs index 34d64799..a77f3a47 100644 --- a/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs +++ b/Source/OpenTK/Platform/MacOS/QuartzDisplayDeviceDriver.cs @@ -83,7 +83,7 @@ namespace OpenTK.Platform.MacOS //Debug.Print("Mode {0} is {1}x{2}x{3} @ {4}.", j, width, height, bpp, freq); - DisplayResolution thisRes = new DisplayResolution(width, height, bpp, (float)freq); + DisplayResolution thisRes = new DisplayResolution(0, 0, width, height, bpp, (float)freq); opentk_dev_available_res.Add(thisRes); if (current) diff --git a/Source/OpenTK/Platform/Utilities.cs b/Source/OpenTK/Platform/Utilities.cs index ea218a5e..e7559f6c 100644 --- a/Source/OpenTK/Platform/Utilities.cs +++ b/Source/OpenTK/Platform/Utilities.cs @@ -217,21 +217,20 @@ namespace OpenTK.Platform #region --- Creating a Graphics Context --- /// - /// Creates a Graphics context and for a window or control. + /// Creates an IGraphicsContext instance for the specified window. /// - /// - /// - /// Major version number of OpenGL context to create. - /// Minor version number of OpenGL context to create. - /// - /// - /// - public static Graphics.GraphicsContext CreateGraphicsContext( - Graphics.GraphicsMode mode, IWindowInfo info, - int major, int minor, OpenTK.Graphics.GraphicsContextFlags flags) + /// The GraphicsMode for the GraphicsContext. + /// An IWindowInfo instance describing the parent window for this IGraphicsContext. + /// The major OpenGL version number for this IGraphicsContext. + /// The minor OpenGL version number for this IGraphicsContext. + /// A bitwise collection of GraphicsContextFlags with specific options for this IGraphicsContext. + /// A new IGraphicsContext instance. + public static Graphics.IGraphicsContext CreateGraphicsContext( + Graphics.GraphicsMode mode, IWindowInfo window, + int major, int minor, Graphics.GraphicsContextFlags flags) { - Graphics.GraphicsContext context = new Graphics.GraphicsContext(mode, info, major, minor, flags); - context.MakeCurrent(info); + Graphics.GraphicsContext context = new Graphics.GraphicsContext(mode, window, major, minor, flags); + context.MakeCurrent(window); (context as OpenTK.Graphics.IGraphicsContextInternal).LoadAll(); @@ -239,29 +238,29 @@ namespace OpenTK.Platform } /// - /// Creates GraphicsContext and IWindowInfo objects for a WinForms control. + /// Creates an IGraphicsContext instance for the specified System.Windows.Forms.Control. /// - /// - /// - /// - /// + /// The GraphicsMode for the GraphicsContext. + /// A System.Windows.Forms.Control. + /// A new IGraphicsContext instance. + /// An IWindowInfo instance for the specified cntrl. [Obsolete("Create the IWindowInfo object first by calling CreateWindowInfo, then use the CreateGraphicsContext overload which takes major, minor and flags parameters.")] public static void CreateGraphicsContext(Graphics.GraphicsMode mode, Control cntrl, - out Graphics.GraphicsContext context, out IWindowInfo info) + out Graphics.IGraphicsContext context, out IWindowInfo info) { CreateGraphicsContext(mode, cntrl.Handle, out context, out info); } /// - /// Creates GraphicsContext and IWindowInfo objects for a WinForms control. + /// Creates an IGraphicsContext instance for the specified System.Windows.Forms.Control. /// - /// - /// - /// - /// + /// The GraphicsMode for the GraphicsContext. + /// A System.IntPtr that contains the handle for a System.Windows.Forms.Control. + /// A new IGraphicsContext instance. + /// An IWindowInfo instance for the specified ctrl. [Obsolete("Create the IWindowInfo object first by calling CreateWindowInfo, then use the CreateGraphicsContext overload which takes major, minor and flags parameters.")] public static void CreateGraphicsContext(Graphics.GraphicsMode mode, IntPtr cntrlHandle, - out Graphics.GraphicsContext context, out IWindowInfo info) + out Graphics.IGraphicsContext context, out IWindowInfo info) { info = CreateWindowInfo(mode, cntrlHandle); diff --git a/Source/OpenTK/Platform/Windows/API.cs b/Source/OpenTK/Platform/Windows/API.cs index 986d7940..e525052c 100644 --- a/Source/OpenTK/Platform/Windows/API.cs +++ b/Source/OpenTK/Platform/Windows/API.cs @@ -28,6 +28,9 @@ namespace OpenTK.Platform.Windows using HWND = System.IntPtr; using HINSTANCE = System.IntPtr; using HMENU = System.IntPtr; + using HICON = System.IntPtr; + using HBRUSH = System.IntPtr; + using HCURSOR = System.IntPtr; using LRESULT = System.IntPtr; using LPVOID = System.IntPtr; @@ -56,6 +59,8 @@ namespace OpenTK.Platform.Windows using WNDPROC = System.IntPtr; using LPDEVMODE = DeviceMode; + using HRESULT = System.IntPtr; + #endregion /// @@ -130,7 +135,10 @@ namespace OpenTK.Platform.Windows /// Found Winuser.h, user32.dll /// [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] - internal static extern BOOL AdjustWindowRect([In, Out] ref RECT lpRect, WindowStyle dwStyle, BOOL bMenu); + internal static extern BOOL AdjustWindowRect([In, Out] ref Rectangle lpRect, WindowStyle dwStyle, BOOL bMenu); + + [DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", CallingConvention = CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity] + internal static extern bool AdjustWindowRectEx(ref Rectangle lpRect, WindowStyle dwStyle, bool bMenu, ExtendedWindowStyle dwExStyle); #endregion @@ -138,16 +146,16 @@ namespace OpenTK.Platform.Windows [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] internal static extern IntPtr CreateWindowEx( - [In]ExtendedWindowStyle ExStyle, - [In]string className, - [In]string windowName, - [In]WindowStyle Style, - [In]int X, int Y, - [In]int Width, int Height, - [In]IntPtr HandleToParentWindow, - [In]IntPtr Menu, - [In]IntPtr Instance, - [In]IntPtr Param); + ExtendedWindowStyle ExStyle, + [MarshalAs(UnmanagedType.LPTStr)] string className, + [MarshalAs(UnmanagedType.LPTStr)] string windowName, + WindowStyle Style, + int X, int Y, + int Width, int Height, + IntPtr HandleToParentWindow, + IntPtr Menu, + IntPtr Instance, + IntPtr Param); /* [DllImport("user32.dll", SetLastError = true)] internal static extern int CreateWindowEx( @@ -165,7 +173,7 @@ namespace OpenTK.Platform.Windows [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] internal static extern IntPtr CreateWindowEx( ExtendedWindowStyle ExStyle, - IntPtr ClassName, + IntPtr ClassAtom, IntPtr WindowName, WindowStyle Style, int X, int Y, @@ -185,79 +193,128 @@ namespace OpenTK.Platform.Windows #region RegisterClass - [DllImport("user32.dll", SetLastError = true)] - internal static extern short RegisterClass(WindowClass window_class); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern ushort RegisterClass(ref WindowClass window_class); + + #endregion + + #region RegisterClassEx + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern ushort RegisterClassEx(ref ExtendedWindowClass window_class); #endregion #region UnregisterClass - [DllImport("user32.dll", SetLastError = true)] - internal static extern short UnregisterClass(string className, IntPtr instance); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern short UnregisterClass([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR className, IntPtr instance); - [DllImport("user32.dll", SetLastError = true)] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] internal static extern short UnregisterClass(IntPtr className, IntPtr instance); #endregion - [CLSCompliant(false)] - [SuppressUnmanagedCodeSecurity] - [DllImport("user32.dll", SetLastError = true)] - internal static extern LRESULT CallWindowProc( - WNDPROC lpPrevWndFunc, - HWND hWnd, - UINT Msg, - WPARAM wParam, - LPARAM lParam - ); + #region GetClassInfoEx + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern BOOL GetClassInfoEx(HINSTANCE hinst, + [MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszClass, ref ExtendedWindowClass lpwcx); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern BOOL GetClassInfoEx(HINSTANCE hinst, UIntPtr lpszClass, ref ExtendedWindowClass lpwcx); + + #endregion + + #region CallWindowProc + +#if RELEASE [SuppressUnmanagedCodeSecurity] +#endif [DllImport("user32.dll", SetLastError = true)] - internal static extern LRESULT CallWindowProc( - WNDPROC lpPrevWndFunc, - HWND hWnd, - INT Msg, - WPARAM wParam, - LPARAM lParam - ); + internal static extern LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, WindowMessage Msg, + WPARAM wParam, LPARAM lParam); + + #endregion #region SetWindowLong - internal static IntPtr SetWindowLong(IntPtr handle, GetWindowLongOffsets index, IntPtr newValue) + // SetWindowLongPtr does not exist on x86 platforms (it's a macro that resolves to SetWindowLong). + // We need to detect if we are on x86 or x64 at runtime and call the correct function + // (SetWindowLongPtr on x64 or SetWindowLong on x86). Fun! + internal static IntPtr SetWindowLong(IntPtr handle, GetWindowLongOffsets item, IntPtr newValue) { - if (IntPtr.Size == 4) - return (IntPtr)SetWindowLong(handle, index, (LONG)newValue); + // SetWindowPos defines its error condition as an IntPtr.Zero retval and a non-0 GetLastError. + // We need to SetLastError(0) to ensure we are not detecting on older error condition (from another function). - return SetWindowLongPtr(handle, index, newValue); + IntPtr retval = IntPtr.Zero; + SetLastError(0); + + if (IntPtr.Size == 4) + retval = new IntPtr(SetWindowLong(handle, item, newValue.ToInt32())); + else + retval = SetWindowLongPtr(handle, item, newValue); + + if (retval == IntPtr.Zero) + { + int error = Marshal.GetLastWin32Error(); + if (error != 0) + throw new PlatformException(String.Format("Failed to modify window border. Error: {0}", error)); + } + + return retval; } + internal static IntPtr SetWindowLong(IntPtr handle, WindowProcedure newValue) + { + return SetWindowLong(handle, GetWindowLongOffsets.WNDPROC, Marshal.GetFunctionPointerForDelegate(newValue)); + } + +#if RELASE [SuppressUnmanagedCodeSecurity] +#endif [DllImport("user32.dll", SetLastError = true)] static extern LONG SetWindowLong(HWND hWnd, GetWindowLongOffsets nIndex, LONG dwNewLong); +#if RELASE [SuppressUnmanagedCodeSecurity] +#endif [DllImport("user32.dll", SetLastError = true)] static extern LONG_PTR SetWindowLongPtr(HWND hWnd, GetWindowLongOffsets nIndex, LONG_PTR dwNewLong); +#if RELASE + [SuppressUnmanagedCodeSecurity] +#endif + [DllImport("user32.dll", SetLastError = true)] + static extern LONG SetWindowLong(HWND hWnd, GetWindowLongOffsets nIndex, + [MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong); + +#if RELASE + [SuppressUnmanagedCodeSecurity] +#endif + [DllImport("user32.dll", SetLastError = true)] + static extern LONG_PTR SetWindowLongPtr(HWND hWnd, GetWindowLongOffsets nIndex, + [MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong); + #endregion #region GetWindowLong - internal static IntPtr GetWindowLong(IntPtr handle, GetWindowLongOffsets index) + internal static UIntPtr GetWindowLong(IntPtr handle, GetWindowLongOffsets index) { if (IntPtr.Size == 4) - return (IntPtr)GetWindowLongInternal(handle, index); + return (UIntPtr)GetWindowLongInternal(handle, index); return GetWindowLongPtrInternal(handle, index); } [SuppressUnmanagedCodeSecurity] [DllImport("user32.dll", SetLastError = true, EntryPoint="GetWindowLong")] - static extern LONG GetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex); + static extern ULONG GetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex); [SuppressUnmanagedCodeSecurity] [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLongPtr")] - static extern LONG_PTR GetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex); + static extern UIntPtr GetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex); #endregion @@ -306,6 +363,13 @@ namespace OpenTK.Platform.Windows #endregion + #region SendMessage + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + internal static extern LRESULT SendMessage(HWND hWnd, WindowMessage Msg, WPARAM wParam, LPARAM lParam); + + #endregion + #region PostMessage [CLSCompliant(false)] @@ -330,12 +394,24 @@ namespace OpenTK.Platform.Windows #region DispatchMessage +#if RELEASE [System.Security.SuppressUnmanagedCodeSecurity] +#endif [DllImport("User32.dll"), CLSCompliant(false)] internal static extern LRESULT DispatchMessage(ref MSG msg); #endregion + #region TranslateMessage + +#if RELEASE + [System.Security.SuppressUnmanagedCodeSecurity] +#endif + [DllImport("User32.dll"), CLSCompliant(false)] + internal static extern BOOL TranslateMessage(ref MSG lpMsg); + + #endregion + #region GetQueueStatus /// @@ -367,6 +443,13 @@ namespace OpenTK.Platform.Windows #endregion + #region DefWindowProc + + [DllImport("User32.dll", CharSet = CharSet.Auto)] + public extern static IntPtr DefWindowProc(HWND hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam); + + #endregion + #endregion #region Timing @@ -428,6 +511,13 @@ namespace OpenTK.Platform.Windows #endregion + #region GetWindowDC + + [DllImport("user32.dll")] + internal static extern IntPtr GetWindowDC(IntPtr hwnd); + + #endregion + #region ReleaseDC /// @@ -493,6 +583,13 @@ namespace OpenTK.Platform.Windows #region DLL handling + #region SetLastError + + [DllImport("kernel32.dll")] + internal static extern void SetLastError(DWORD dwErrCode); + + #endregion + #region GetModuleHandle [DllImport("kernel32.dll")] @@ -594,8 +691,8 @@ namespace OpenTK.Platform.Windows /// The SetWindowText function does not expand tab characters (ASCII code 0x09). Tab characters are displayed as vertical bar (|) characters. /// Windows 95/98/Me: SetWindowTextW is supported by the Microsoft Layer for Unicode (MSLU). To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems . /// - [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] - internal static extern BOOL SetWindowText(HWND hWnd, LPCTSTR lpString); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern BOOL SetWindowText(HWND hWnd, [MarshalAs(UnmanagedType.LPTStr)] string lpString); #endregion @@ -616,9 +713,8 @@ namespace OpenTK.Platform.Windows /// To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead of calling GetWindowText. /// Windows 95/98/Me: GetWindowTextW is supported by the Microsoft Layer for Unicode (MSLU). To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me /// - [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] - internal static extern int GetWindowText(HWND hWnd, - [MarshalAs(UnmanagedType.LPTStr), Out] StringBuilder lpString, int nMaxCount); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + internal static extern int GetWindowText(HWND hWnd, [MarshalAs(UnmanagedType.LPTStr), In, Out] StringBuilder lpString, int nMaxCount); #endregion @@ -672,7 +768,24 @@ namespace OpenTK.Platform.Windows /// /// In conformance with conventions for the RECT structure, the bottom-right coordinates of the returned rectangle are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle. [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] - internal extern static BOOL GetClientRect(HWND windowHandle, out RECT clientRectangle); + internal extern static BOOL GetClientRect(HWND windowHandle, out Rectangle clientRectangle); + + #endregion + + #region GetWindowRect + + /// + /// The GetWindowRect function retrieves the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen. + /// + /// Handle to the window whose client coordinates are to be retrieved. + /// Pointer to a structure that receives the screen coordinates of the upper-left and lower-right corners of the window. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// + /// In conformance with conventions for the RECT structure, the bottom-right coordinates of the returned rectangle are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle. + [DllImport("user32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity] + internal extern static BOOL GetWindowRect(HWND windowHandle, out Rectangle windowRectangle); #endregion @@ -683,6 +796,20 @@ namespace OpenTK.Platform.Windows #endregion + #region DwmGetWindowAttribute + + [DllImport("dwmapi.dll")] + unsafe public static extern HRESULT DwmGetWindowAttribute(HWND hwnd, DwmWindowAttribute dwAttribute, void* pvAttribute, DWORD cbAttribute); + + #endregion + + #region GetFocus + + [DllImport("user32.dll")] + public static extern HWND GetFocus(); + + #endregion + #endregion #region Display settings @@ -706,40 +833,47 @@ namespace OpenTK.Platform.Windows #region ChangeDisplaySettingsEx - [DllImport("user32.dll", SetLastError = true)] - public static extern LONG ChangeDisplaySettingsEx(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, - HWND hwnd, ChangeDisplaySettingsEnum dwflags, LPVOID lParam); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern LONG ChangeDisplaySettingsEx([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszDeviceName, + LPDEVMODE lpDevMode, HWND hwnd, ChangeDisplaySettingsEnum dwflags, LPVOID lParam); #endregion #region EnumDisplayDevices - [DllImport("user32.dll", SetLastError = true)] + [DllImport("user32.dll", SetLastError = true, CharSet=CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern BOOL EnumDisplayDevices([MarshalAs(UnmanagedType.LPStr)] LPCTSTR lpDevice, + public static extern BOOL EnumDisplayDevices([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpDevice, DWORD iDevNum, [In, Out] WindowsDisplayDevice lpDisplayDevice, DWORD dwFlags); #endregion #region EnumDisplaySettings - [DllImport("user32.dll", SetLastError = true)] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] - internal static extern BOOL EnumDisplaySettings([MarshalAs(UnmanagedType.LPStr)] string device_name, - int graphics_mode, [Out] DeviceMode device_mode); + internal static extern BOOL EnumDisplaySettings([MarshalAs(UnmanagedType.LPTStr)] string device_name, + int graphics_mode, [In, Out] DeviceMode device_mode); - [DllImport("user32.dll", SetLastError = true)] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] - internal static extern BOOL EnumDisplaySettings([MarshalAs(UnmanagedType.LPStr)] string device_name, - DisplayModeSettingsEnum graphics_mode, [Out] DeviceMode device_mode); + internal static extern BOOL EnumDisplaySettings([MarshalAs(UnmanagedType.LPTStr)] string device_name, + DisplayModeSettingsEnum graphics_mode, [In, Out] DeviceMode device_mode); #endregion #region EnumDisplaySettingsEx + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern BOOL EnumDisplaySettingsEx([MarshalAs(UnmanagedType.LPTStr)] LPCTSTR lpszDeviceName, DisplayModeSettingsEnum iModeNum, + [In, Out] DeviceMode lpDevMode, DWORD dwFlags); + + #endregion + + #region GetMonitorInfo + [DllImport("user32.dll", SetLastError = true)] - public static extern BOOL EnumDisplaySettingsEx([MarshalAs(UnmanagedType.LPStr)] LPCTSTR lpszDeviceName, DisplayModeSettingsEnum iModeNum, - [Out] DeviceMode lpDevMode, DWORD dwFlags); + public static extern BOOL GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi); #endregion @@ -1240,6 +1374,17 @@ namespace OpenTK.Platform.Windows #endregion + #region GDI functions + + #region GetStockObject + + [DllImport("gdi32.dll", SetLastError = true)] + internal static extern IntPtr GetStockObject(int index); + + #endregion + + #endregion + #endregion } @@ -1428,6 +1573,26 @@ namespace OpenTK.Platform.Windows #endregion + #region StyleStruct + + struct StyleStruct + { + public WindowStyle Old; + public WindowStyle New; + } + + #endregion + + #region ExtendedStyleStruct + + struct ExtendedStyleStruct + { + public ExtendedWindowStyle Old; + public ExtendedWindowStyle New; + } + + #endregion + #region PixelFormatDescriptor /// @@ -1613,7 +1778,7 @@ namespace OpenTK.Platform.Windows #endif } DEVMODE; */ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal class DeviceMode { internal DeviceMode() @@ -1629,14 +1794,18 @@ namespace OpenTK.Platform.Windows internal short DriverExtra; internal int Fields; - internal short Orientation; - internal short PaperSize; - internal short PaperLength; - internal short PaperWidth; - internal short Scale; - internal short Copies; - internal short DefaultSource; - internal short PrintQuality; + //internal short Orientation; + //internal short PaperSize; + //internal short PaperLength; + //internal short PaperWidth; + //internal short Scale; + //internal short Copies; + //internal short DefaultSource; + //internal short PrintQuality; + + internal POINT Position; + internal DWORD DisplayOrientation; + internal DWORD DisplayFixedOutput; internal short Color; internal short Duplex; @@ -1668,7 +1837,7 @@ namespace OpenTK.Platform.Windows /// /// The DISPLAY_DEVICE structure receives information about the display device specified by the iDevNum parameter of the EnumDisplayDevices function. /// - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal class WindowsDisplayDevice { internal WindowsDisplayDevice() @@ -1693,11 +1862,11 @@ namespace OpenTK.Platform.Windows #region WindowClass [StructLayout(LayoutKind.Sequential)] - internal class WindowClass + internal struct WindowClass { - internal WindowClassStyle style = WindowClassStyle.VRedraw | WindowClassStyle.HRedraw | WindowClassStyle.OwnDC; + internal ClassStyle Style; [MarshalAs(UnmanagedType.FunctionPtr)] - internal WindowProcedureEventHandler WindowProcedure; + internal WindowProcedure WindowProcedure; internal int ClassExtraBytes; internal int WindowExtraBytes; //[MarshalAs(UnmanagedType. @@ -1707,12 +1876,39 @@ namespace OpenTK.Platform.Windows internal IntPtr BackgroundBrush; //[MarshalAs(UnmanagedType.LPStr)] internal IntPtr MenuName; - //[MarshalAs(UnmanagedType.LPStr)] - internal IntPtr ClassName; + [MarshalAs(UnmanagedType.LPTStr)] + internal string ClassName; //internal string ClassName; + + internal static int SizeInBytes = Marshal.SizeOf(default(WindowClass)); } #endregion + #region ExtendedWindowClass + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct ExtendedWindowClass + { + public UINT Size; + public ClassStyle Style; + //public WNDPROC WndProc; + [MarshalAs(UnmanagedType.FunctionPtr)] + public WindowProcedure WndProc; + public int cbClsExtra; + public int cbWndExtra; + public HINSTANCE Instance; + public HICON Icon; + public HCURSOR Cursor; + public HBRUSH Background; + public IntPtr MenuName; + public IntPtr ClassName; + public HICON IconSm; + + public static uint SizeInBytes = (uint)Marshal.SizeOf(default(ExtendedWindowClass)); + } + + #endregion + #region internal struct MinMaxInfo /// @@ -1721,11 +1917,11 @@ namespace OpenTK.Platform.Windows [StructLayout(LayoutKind.Sequential)] internal struct MINMAXINFO { - System.Drawing.Point ptReserved; - System.Drawing.Point ptMaxSize; - System.Drawing.Point ptMaxPosition; - System.Drawing.Point ptMinTrackSize; - System.Drawing.Point ptMaxTrackSize; + System.Drawing.Point Reserved; + public System.Drawing.Size MaxSize; + public System.Drawing.Point MaxPosition; + public System.Drawing.Size MinTrackSize; + public System.Drawing.Size MaxTrackSize; } #endregion @@ -2326,30 +2522,6 @@ namespace OpenTK.Platform.Windows #region GetWindowLongOffsets - /// - /// Window field offsets for GetWindowLong() and GetWindowLongPtr(). - /// - internal static class GWL - { - private static bool x64; - static GWL() - { - unsafe - { - x64 = sizeof(void*) == 8; - } - - } - - internal static readonly int WNDPROC = (-4); - internal static readonly int HINSTANCE = (-6); - internal static readonly int HWNDPARENT = (-8); - internal static readonly int STYLE = (-16); - internal static readonly int EXSTYLE = (-20); - internal static readonly int USERDATA = (-21); - internal static readonly int ID = (-12); - } - #endregion #region Rectangle @@ -2394,6 +2566,31 @@ namespace OpenTK.Platform.Windows { return String.Format("({0},{1})-({2},{3})", left, top, right, bottom); } + + internal System.Drawing.Rectangle ToRectangle() + { + return System.Drawing.Rectangle.FromLTRB(left, top, right, bottom); + } + + internal static Rectangle From(System.Drawing.Rectangle value) + { + Rectangle rect = new Rectangle(); + rect.left = value.Left; + rect.right = value.Right; + rect.top = value.Top; + rect.bottom = value.Bottom; + return rect; + } + + internal static Rectangle From(System.Drawing.Size value) + { + Rectangle rect = new Rectangle(); + rect.left = 0; + rect.right = value.Width; + rect.top = 0; + rect.bottom = value.Height; + return rect; + } } #endregion @@ -2450,12 +2647,70 @@ namespace OpenTK.Platform.Windows #endregion + #region MonitorInfo + + struct MonitorInfo + { + public DWORD Size; + public RECT Monitor; + public RECT Work; + public DWORD Flags; + + public static readonly int SizeInBytes = Marshal.SizeOf(default(MonitorInfo)); + } + + #endregion + + #region NcCalculateSize + + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct NcCalculateSize + { + public Rectangle NewBounds; + public Rectangle OldBounds; + public Rectangle OldClientRectangle; + unsafe public WindowPosition* Position; + } + + #endregion + #endregion #region --- Enums --- - #region - + #region GetWindowLongOffset + + /// + /// Window field offsets for GetWindowLong() and GetWindowLongPtr(). + /// + enum GWL + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12), + } + + #endregion + + #region SizeMessage + + internal enum SizeMessage + { + MAXHIDE = 4, + MAXIMIZED = 2, + MAXSHOW = 3, + MINIMIZED = 1, + RESTORED = 0 + } + + #endregion + + #region NcCalcSizeOptions + internal enum NcCalcSizeOptions { ALIGNTOP = 0x10, @@ -2516,13 +2771,13 @@ namespace OpenTK.Platform.Windows #endregion - #region internal enum WindowStyle : int + #region internal enum WindowStyle : uint [Flags] - internal enum WindowStyle : int + internal enum WindowStyle : uint { Overlapped = 0x00000000, - Popup = unchecked((int)0x80000000), + Popup = 0x80000000, Child = 0x40000000, Minimize = 0x20000000, Visible = 0x10000000, @@ -2556,10 +2811,10 @@ namespace OpenTK.Platform.Windows #endregion - #region internal enum ExtendedWindowStyle : int + #region internal enum ExtendedWindowStyle : uint [Flags] - internal enum ExtendedWindowStyle : int + internal enum ExtendedWindowStyle : uint { DialogModalFrame = 0x00000001, NoParentNotify = 0x00000004, @@ -2675,9 +2930,9 @@ namespace OpenTK.Platform.Windows #endregion - #region WindowClassStyle enum + #region ClassStyle enum [Flags] - internal enum WindowClassStyle + internal enum ClassStyle { //None = 0x0000, VRedraw = 0x0001, @@ -3232,7 +3487,7 @@ namespace OpenTK.Platform.Windows #region WindowMessage - internal enum WindowMessage + internal enum WindowMessage : uint { NULL = 0x0000, CREATE = 0x0001, @@ -3523,7 +3778,7 @@ namespace OpenTK.Platform.Windows /// Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time. /// SHOWNORMAL = 1, - //NORMAL = 1, + NORMAL = 1, /// /// Activates the window and displays it as a minimized window. /// @@ -3532,7 +3787,7 @@ namespace OpenTK.Platform.Windows /// Activates the window and displays it as a maximized window. /// SHOWMAXIMIZED = 3, - //MAXIMIZE = 3, + MAXIMIZE = 3, /// /// Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated. /// @@ -3641,24 +3896,32 @@ namespace OpenTK.Platform.Windows #endregion + #region DwmWindowAttribute + + enum DwmWindowAttribute + { + NCRENDERING_ENABLED = 1, + NCRENDERING_POLICY, + TRANSITIONS_FORCEDISABLED, + ALLOW_NCPAINT, + CAPTION_BUTTON_BOUNDS, + NONCLIENT_RTL_LAYOUT, + FORCE_ICONIC_REPRESENTATION, + FLIP3D_POLICY, + EXTENDED_FRAME_BOUNDS, + HAS_ICONIC_BITMAP, + DISALLOW_PEEK, + EXCLUDED_FROM_PEEK, + LAST + } + + #endregion + #endregion #region --- Callbacks --- - internal delegate void WindowProcedure(ref System.Windows.Forms.Message msg); - - [UnmanagedFunctionPointerAttribute(CallingConvention.Winapi)] - internal delegate void WindowProcedureEventHandler(object sender, WindowProcedureEventArgs e); - - internal class WindowProcedureEventArgs : EventArgs - { - private System.Windows.Forms.Message msg; - internal System.Windows.Forms.Message Message - { - get { return msg; } - set { msg = value; } - } - } + internal delegate IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam); #region Message diff --git a/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs b/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs index 16f1536d..33d9fbc2 100644 --- a/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs +++ b/Source/OpenTK/Platform/Windows/WinDisplayDevice.cs @@ -52,10 +52,12 @@ namespace OpenTK.Platform.Windows // The second function should only be executed when the first one fails // (e.g. when the monitor is disabled) - if (Functions.EnumDisplaySettings(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.CurrentSettings, monitor_mode) || - Functions.EnumDisplaySettings(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.RegistrySettings, monitor_mode)) + if (Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.CurrentSettings, monitor_mode, 0) || + Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.RegistrySettings, monitor_mode, 0)) { - opentk_dev_current_res = new DisplayResolution(monitor_mode.PelsWidth, monitor_mode.PelsHeight, + opentk_dev_current_res = new DisplayResolution( + monitor_mode.Position.X, monitor_mode.Position.Y, + monitor_mode.PelsWidth, monitor_mode.PelsHeight, monitor_mode.BitsPerPel, monitor_mode.DisplayFrequency); opentk_dev_primary = (dev1.StateFlags & DisplayDeviceStateFlags.PrimaryDevice) != DisplayDeviceStateFlags.None; @@ -66,6 +68,7 @@ namespace OpenTK.Platform.Windows while (Functions.EnumDisplaySettings(dev1.DeviceName.ToString(), mode_count++, monitor_mode)) { DisplayResolution res = new DisplayResolution( + monitor_mode.Position.X, monitor_mode.Position.Y, monitor_mode.PelsWidth, monitor_mode.PelsHeight, monitor_mode.BitsPerPel, monitor_mode.DisplayFrequency); @@ -75,7 +78,9 @@ namespace OpenTK.Platform.Windows // Construct the OpenTK DisplayDevice through the accumulated parameters. // The constructor will automatically add the DisplayDevice to the list // of available devices. - opentk_dev = new OpenTK.Graphics.DisplayDevice(opentk_dev_current_res, opentk_dev_primary, + opentk_dev = new OpenTK.Graphics.DisplayDevice( + opentk_dev_current_res, + opentk_dev_primary, opentk_dev_available_res); available_device_names.Add(opentk_dev, dev1.DeviceName); diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs index 2479e6fd..11f445ae 100644 --- a/Source/OpenTK/Platform/Windows/WinFactory.cs +++ b/Source/OpenTK/Platform/Windows/WinFactory.cs @@ -1,3 +1,30 @@ +#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.Collections.Generic; using System.Text; @@ -13,7 +40,12 @@ using OpenTK.Input; public INativeGLWindow CreateGLNative() { - return new WinGLNative(); + throw new NotSupportedException(); + } + + public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) + { + return new WinGLNative(x, y, width, height, title, options, device); } public IGLControl CreateGLControl(GraphicsMode mode, GLControl owner) @@ -28,7 +60,7 @@ using OpenTK.Input; public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags) { - return new WinGLContext(mode, window, shareContext, major, minor, flags); + return new WinGLContext(mode, (WinWindowInfo)window, shareContext, major, minor, flags); } public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index 6e049a58..fbdca6cc 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -26,12 +26,10 @@ namespace OpenTK.Platform.Windows /// internal sealed class WinGLContext : IGraphicsContext, IGraphicsContextInternal//, IGLContextCreationHack { - WinWindowInfo currentWindow; ContextHandle renderContext; static IntPtr opengl32Handle; static bool wgl_loaded; const string opengl32Name = "OPENGL32.DLL"; - //WinWindowInfo windowInfo = new WinWindowInfo(); GraphicsMode format; //DisplayMode mode = null; @@ -54,18 +52,17 @@ namespace OpenTK.Platform.Windows } } - public WinGLContext(GraphicsMode format, IWindowInfo window, IGraphicsContext sharedContext, + public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext, int major, int minor, GraphicsContextFlags flags) { if (window == null) throw new ArgumentNullException("window", "Must point to a valid window."); - currentWindow = (WinWindowInfo)window; - if (currentWindow.WindowHandle == IntPtr.Zero) + if (window.WindowHandle == IntPtr.Zero) throw new ArgumentException("window", "Must be a valid window."); this.format = format; - Debug.Print("OpenGL will be bound to handle: {0}", currentWindow.WindowHandle); + Debug.Print("OpenGL will be bound to handle: {0}", window.WindowHandle); Debug.Write("Setting pixel format... "); this.SetGraphicsModePFD(format, (WinWindowInfo)window); @@ -75,8 +72,8 @@ namespace OpenTK.Platform.Windows // We cannot rely on OpenTK.Platform.Wgl until we create the context and call Wgl.LoadAll(). Debug.Print("Creating temporary context for wgl extensions."); - ContextHandle temp_context = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext)); - Wgl.Imports.MakeCurrent(currentWindow.DeviceContext, temp_context.Handle); + ContextHandle temp_context = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext)); + Wgl.Imports.MakeCurrent(window.DeviceContext, temp_context.Handle); Wgl.LoadAll(); Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); Wgl.DeleteContext(temp_context.Handle); @@ -103,7 +100,7 @@ namespace OpenTK.Platform.Windows renderContext = new ContextHandle( Wgl.Arb.CreateContextAttribs( - currentWindow.DeviceContext, + window.DeviceContext, sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero, attributes.ToArray())); if (renderContext == ContextHandle.Zero) @@ -119,9 +116,9 @@ namespace OpenTK.Platform.Windows { // Failed to create GL3-level context, fall back to GL2. Debug.Write("Falling back to GL2... "); - renderContext = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext)); + renderContext = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext)); if (renderContext == ContextHandle.Zero) - renderContext = new ContextHandle(Wgl.Imports.CreateContext(currentWindow.DeviceContext)); + renderContext = new ContextHandle(Wgl.Imports.CreateContext(window.DeviceContext)); if (renderContext == ContextHandle.Zero) throw new GraphicsContextException( String.Format("Context creation failed. Wgl.CreateContext() error: {0}.", @@ -145,7 +142,7 @@ namespace OpenTK.Platform.Windows public void SwapBuffers() { - if (!Functions.SwapBuffers(currentWindow.DeviceContext)) + if (!Functions.SwapBuffers(Wgl.GetCurrentDC())) throw new GraphicsContextException(String.Format( "Failed to swap buffers for context {0} current. Error: {1}", this, Marshal.GetLastWin32Error())); } @@ -163,7 +160,6 @@ namespace OpenTK.Platform.Windows if (((WinWindowInfo)window).WindowHandle == IntPtr.Zero) throw new ArgumentException("window", "Must point to a valid window."); - currentWindow = (WinWindowInfo)window; success = Wgl.Imports.MakeCurrent(((WinWindowInfo)window).DeviceContext, this.renderContext.Handle); } else @@ -352,9 +348,7 @@ namespace OpenTK.Platform.Windows { get { - if (currentWindow != null) - return currentWindow.DeviceContext; - return IntPtr.Zero; + return Wgl.GetCurrentDC(); } } @@ -392,7 +386,8 @@ namespace OpenTK.Platform.Windows } else { - Debug.Print("[Warning] OpenGL context {0} leaked. Did you forget to call IGraphicsContext.Dispose()?", renderContext.Handle); + Debug.Print("[Warning] OpenGL context {0} leaked. Did you forget to call IGraphicsContext.Dispose()?", + renderContext.Handle); } disposed = true; } diff --git a/Source/OpenTK/Platform/Windows/WinGLControl.cs b/Source/OpenTK/Platform/Windows/WinGLControl.cs index f72c39c8..8bd7fe22 100644 --- a/Source/OpenTK/Platform/Windows/WinGLControl.cs +++ b/Source/OpenTK/Platform/Windows/WinGLControl.cs @@ -46,7 +46,7 @@ namespace OpenTK.Platform.Windows public GraphicsContext CreateContext(int major, int minor, GraphicsContextFlags flags) { - // Make sure the Control exists before creating the context. + // Make sure the Control exists before create the context. if (window_info == null) window_info = new WinWindowInfo(control.Handle, null); diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index 9af50437..aca7c558 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -1,23 +1,38 @@ -#region --- License --- -/* Copyright (c) 2007 Stefanos Apostolopoulos - * See license.txt for license info - */ +#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 -#region --- Using directives --- - using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Windows.Forms; using System.Diagnostics; -using OpenTK.Graphics.OpenGL; -using OpenTK.Input; -using OpenTK.Graphics; using System.Drawing; - -#endregion +using System.Runtime.InteropServices; +using System.Text; +using OpenTK.Graphics; +using OpenTK.Input; +using System.Collections.Generic; namespace OpenTK.Platform.Windows { @@ -25,107 +40,184 @@ namespace OpenTK.Platform.Windows /// Drives GameWindow on Windows. /// This class supports OpenTK, and is not intended for use by OpenTK programs. /// - internal sealed class WinGLNative : System.Windows.Forms.NativeWindow, INativeGLWindow + internal sealed class WinGLNative : INativeWindow, IInputDriver { - #region --- Fields --- + #region Fields - private IInputDriver driver; + readonly static ExtendedWindowStyle ParentStyleEx = ExtendedWindowStyle.WindowEdge; + readonly static ExtendedWindowStyle ChildStyleEx = 0; - private bool visible = true; - private bool disposed; - private bool isExiting; - private bool exists; - private WinWindowInfo window; - private WindowBorder windowBorder = WindowBorder.Resizable, previous_window_border; - private WindowState windowState = WindowState.Normal; + readonly IntPtr Instance = Marshal.GetHINSTANCE(typeof(WinGLNative).Module); + readonly IntPtr ClassName = Marshal.StringToHGlobalAuto("OpenTK.INativeWindow" + WindowCount++.ToString()); + readonly WindowProcedure WindowProcedureDelegate; - private int top, bottom, left, right; - //private int width = 0, height = 0; - private Rectangle previous_client_area; + bool class_registered; + bool visible = true; + bool disposed; + bool exists; + WinWindowInfo window, child_window; + WindowBorder windowBorder = WindowBorder.Resizable, previous_window_border; + WindowState windowState = WindowState.Normal; - private Point position = new Point(); - private Rectangle client_rectangle = new Rectangle(); - private Size window_size = new Size(); - //private Rectangle borders = new Rectangle(); + System.Drawing.Rectangle bounds = new System.Drawing.Rectangle(); + System.Drawing.Rectangle client_rectangle = new System.Drawing.Rectangle(); + Icon icon; - private ResizeEventArgs resizeEventArgs = new ResizeEventArgs(); + static readonly ClassStyle ClassStyle = + ClassStyle.OwnDC | ClassStyle.VRedraw | ClassStyle.HRedraw | ClassStyle.Ime; - /// - /// For use in PeekMessage. - /// - private MSG myGoodMsg = new MSG(); + static int WindowCount = 0; // Used to create unique window class names. - private int left_border, right_border, top_border, bottom_border; + IntPtr DefaultWindowProcedure = + Marshal.GetFunctionPointerForDelegate(new WindowProcedure(Functions.DefWindowProc)); + + // Used for IInputDriver implementation + WinMMJoystick joystick_driver = new WinMMJoystick(); + KeyboardDevice keyboard = new KeyboardDevice(); + MouseDevice mouse = new MouseDevice(); + IList keyboards = new List(1); + IList mice = new List(1); + internal static readonly WinKeyMap KeyMap = new WinKeyMap(); + const long ExtendedBit = 1 << 24; // Used to distinguish left and right control, alt and enter keys. + static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0); // Used to distinguish left and right shift keys. #endregion - #region --- Contructors --- + #region Contructors - /// - /// - /// Constructs a new WinGLNative class. Call CreateWindow to create the - /// actual render window. - /// - internal WinGLNative() + public WinGLNative(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device) { - Debug.Print("Native window driver: {0}", this.ToString()); + // This is the main window procedure callback. We need the callback in order to create the window, so + // don't move it below the CreateWindow calls. + WindowProcedureDelegate = WindowProcedure; + + // To avoid issues with Ati drivers on Windows 6+ with compositing enabled, the context will not be + // bound to the top-level window, but rather to a child window docked in the parent. + window = new WinWindowInfo( + CreateWindow(x, y, width, height, title, options, device, IntPtr.Zero), null); + child_window = new WinWindowInfo( + CreateWindow(0, 0, ClientSize.Width, ClientSize.Height, title, options, device, window.WindowHandle), window); + + exists = true; + + keyboard.Description = "Standard Windows keyboard"; + keyboard.NumberOfFunctionKeys = 12; + keyboard.NumberOfKeys = 101; + keyboard.NumberOfLeds = 3; + + mouse.Description = "Standard Windows mouse"; + mouse.NumberOfButtons = 3; + mouse.NumberOfWheels = 1; + + keyboards.Add(keyboard); + mice.Add(mouse); } #endregion - #region --- Protected Members --- + #region Private Members - #region protected override void WndProc(ref Message m) + #region WindowProcedure - /// - /// Processes incoming WM_* messages. - /// - /// Reference to the incoming Windows Message. - protected override void WndProc(ref Message m) + IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) { - switch ((WindowMessage)m.Msg) + bool mouse_about_to_enter = false; + + switch (message) { + #region Size / Move events + case WindowMessage.ACTIVATE: break; case WindowMessage.NCCALCSIZE: // Need to update the client rectangle, because it has the wrong size on Vista with Aero enabled. + //if (m.WParam == new IntPtr(1)) + //{ + // unsafe + // { + // NcCalculateSize* nc_calc_size = (NcCalculateSize*)m.LParam; + // //nc_calc_size->NewBounds = nc_calc_size->OldBounds; + // //nc_calc_size->OldBounds = nc_calc_size->NewBounds; + // //client_rectangle = rect.OldClientRectangle; + // } + + // m.Result = new IntPtr((int)(NcCalcSizeOptions.ALIGNTOP | NcCalcSizeOptions.ALIGNLEFT/* | NcCalcSizeOptions.REDRAW*/)); + //} break; + case WindowMessage.ERASEBKGND: + return new IntPtr(1); + case WindowMessage.WINDOWPOSCHANGED: - WindowPosition pos = (WindowPosition)Marshal.PtrToStructure(m.LParam, typeof(WindowPosition)); - position.X = pos.x; - position.Y = pos.y; + unsafe + { + WindowPosition* pos = (WindowPosition*)lParam; + if (window != null && pos->hwnd == window.WindowHandle) + { + Point new_location = new Point(pos->x, pos->y); + if (Location != new_location) + { + bounds.Location = new_location; + if (Move != null) + Move(this, EventArgs.Empty); + } - window_size.Width = pos.cx; - window_size.Height = pos.cy; + Size new_size = new Size(pos->cx, pos->cy); + if (Size != new_size) + { + bounds.Width = pos->cx; + bounds.Height = pos->cy; - Functions.GetClientRect(Handle, out client_rectangle); + Rectangle rect; + Functions.GetClientRect(handle, out rect); + client_rectangle = rect.ToRectangle(); + Functions.SetWindowPos(child_window.WindowHandle, IntPtr.Zero, 0, 0, ClientRectangle.Width, ClientRectangle.Height, + SetWindowPosFlags.NOZORDER | SetWindowPosFlags.NOOWNERZORDER | + SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING); + + if (Resize != null) + Resize(this, EventArgs.Empty); + } + } + } break; case WindowMessage.STYLECHANGED: - WindowStyle style = (WindowStyle)(long)Functions.GetWindowLong(Handle, GetWindowLongOffsets.STYLE); - if ((style & WindowStyle.Popup) != 0) - windowBorder = WindowBorder.Hidden; - else if ((style & WindowStyle.ThickFrame) != 0) - windowBorder = WindowBorder.Resizable; - else if ((style & ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox)) != 0) - windowBorder = WindowBorder.Fixed; + unsafe + { + if (wParam.ToInt64() == (long)GWL.STYLE) + { + WindowStyle style = ((StyleStruct*)lParam)->New; + if ((style & WindowStyle.Popup) != 0) + windowBorder = WindowBorder.Hidden; + else if ((style & WindowStyle.ThickFrame) != 0) + windowBorder = WindowBorder.Resizable; + else if ((style & ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox)) != 0) + windowBorder = WindowBorder.Fixed; + } + } + break; case WindowMessage.SIZE: - long state = m.WParam.ToInt64(); + SizeMessage state = (SizeMessage)wParam.ToInt64(); switch (state) { - case 0: windowState = WindowState.Normal; break; - case 1: windowState = WindowState.Minimized; break; - case 2: + case SizeMessage.RESTORED: windowState = WindowState.Normal; break; + case SizeMessage.MINIMIZED: windowState = WindowState.Minimized; break; + case SizeMessage.MAXIMIZED: windowState = WindowBorder == WindowBorder.Hidden ? WindowState.Fullscreen : WindowState.Maximized; break; } + break; + #endregion + + #region Input events + //case WindowMessage.MOUSELEAVE: // Cursor.Current = Cursors.Default; // break; @@ -134,144 +226,488 @@ namespace OpenTK.Platform.Windows // Cursor.Current = Cursors.Default; // break; - case WindowMessage.CREATE: - // Set the window width and height: - pos = (WindowPosition)Marshal.PtrToStructure(m.LParam, typeof(WindowPosition)); - position.X = pos.x; - position.Y = pos.y; - - window_size.Width = pos.cx; - window_size.Height = pos.cy; - - // Raise the Create event - this.OnCreate(EventArgs.Empty); - return; - - case WindowMessage.CLOSE: - //this.DestroyWindow(); - this.OnDestroy(EventArgs.Empty); - return; - //break; - - case WindowMessage.DESTROY: - //this.OnDestroy(EventArgs.Empty); - exists = false; - isExiting = true; + // Mouse events: + case WindowMessage.NCMOUSEMOVE: + mouse_about_to_enter = true; // Used to simulate a mouse enter event. break; - case WindowMessage.QUIT: - isExiting = true; - //this.Dispose(); - //Debug.WriteLine("Application quit."); - return; + case WindowMessage.MOUSEMOVE: + mouse.Position = new System.Drawing.Point( + (int)(lParam.ToInt32() & 0x0000FFFF), + (int)(lParam.ToInt32() & 0xFFFF0000) >> 16); + if (mouse_about_to_enter) + { + //Cursor.Current = Cursors.Default; + mouse_about_to_enter = false; + } + break; + + case WindowMessage.MOUSEWHEEL: + // This is due to inconsistent behavior of the WParam value on 64bit arch, whese + // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000 + mouse.Wheel += (int)((long)wParam << 32 >> 48) / 120; + break; + + case WindowMessage.LBUTTONDOWN: + mouse[MouseButton.Left] = true; + break; + + case WindowMessage.MBUTTONDOWN: + mouse[MouseButton.Middle] = true; + break; + + case WindowMessage.RBUTTONDOWN: + mouse[MouseButton.Right] = true; + break; + + case WindowMessage.XBUTTONDOWN: + mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = true; + break; + + case WindowMessage.LBUTTONUP: + mouse[MouseButton.Left] = false; + break; + + case WindowMessage.MBUTTONUP: + mouse[MouseButton.Middle] = false; + break; + + case WindowMessage.RBUTTONUP: + mouse[MouseButton.Right] = false; + break; + + case WindowMessage.XBUTTONUP: + // TODO: Is this correct? + mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = false; + break; + + // Keyboard events: + case WindowMessage.KEYDOWN: + case WindowMessage.KEYUP: + case WindowMessage.SYSKEYDOWN: + case WindowMessage.SYSKEYUP: + bool pressed = + message == WindowMessage.KEYDOWN || + message == WindowMessage.SYSKEYDOWN; + + // Shift/Control/Alt behave strangely when e.g. ShiftRight is held down and ShiftLeft is pressed + // and released. It looks like neither key is released in this case, or that the wrong key is + // released in the case of Control and Alt. + // To combat this, we are going to release both keys when either is released. Hacky, but should work. + // Win95 does not distinguish left/right key constants (GetAsyncKeyState returns 0). + // In this case, both keys will be reported as pressed. + + bool extended = (lParam.ToInt64() & ExtendedBit) != 0; + switch ((VirtualKeys)wParam) + { + case VirtualKeys.SHIFT: + // The behavior of this key is very strange. Unlike Control and Alt, there is no extended bit + // to distinguish between left and right keys. Moreover, pressing both keys and releasing one + // may result in both keys being held down (but not always). + // The only reliably way to solve this was reported by BlueMonkMN at the forums: we should + // check the scancodes. It looks like GLFW does the same thing, so it should be reliable. + + // TODO: Not 100% reliable, when both keys are pressed at once. + if (ShiftRightScanCode != 0) + { + unchecked + { + if (((lParam.ToInt64() >> 16) & 0xFF) == ShiftRightScanCode) + keyboard[Input.Key.ShiftRight] = pressed; + else + keyboard[Input.Key.ShiftLeft] = pressed; + } + } + else + { + // Should only fall here on Windows 9x and NT4.0- + keyboard[Input.Key.ShiftLeft] = pressed; + } + return IntPtr.Zero; + + case VirtualKeys.CONTROL: + if (extended) + keyboard[Input.Key.ControlRight] = pressed; + else + keyboard[Input.Key.ControlLeft] = pressed; + return IntPtr.Zero; + + case VirtualKeys.MENU: + if (extended) + keyboard[Input.Key.AltRight] = pressed; + else + keyboard[Input.Key.AltLeft] = pressed; + return IntPtr.Zero; + + case VirtualKeys.RETURN: + if (extended) + keyboard[Key.KeypadEnter] = pressed; + else + keyboard[Key.Enter] = pressed; + return IntPtr.Zero; + + default: + if (!WMInput.KeyMap.ContainsKey((VirtualKeys)wParam)) + { + Debug.Print("Virtual key {0} ({1}) not mapped.", (VirtualKeys)wParam, (int)lParam); + break; + } + else + { + keyboard[WMInput.KeyMap[(VirtualKeys)wParam]] = pressed; + } + return IntPtr.Zero; + } + break; + + case WindowMessage.KILLFOCUS: + keyboard.ClearKeys(); + break; + + #endregion + + #region Creation / Destruction events + + case WindowMessage.CREATE: + CreateStruct cs = (CreateStruct)Marshal.PtrToStructure(lParam, typeof(CreateStruct)); + if (cs.hwndParent == IntPtr.Zero) + { + bounds.X = cs.x; + bounds.Y = cs.y; + bounds.Width = cs.cx; + bounds.Height = cs.cy; + + Rectangle rect; + Functions.GetClientRect(handle, out rect); + client_rectangle = rect.ToRectangle(); + } + break; + + case WindowMessage.GETICON: + if (icon != null) + { + icon.Dispose(); + icon = null; + } + + if (lParam != IntPtr.Zero) + { + icon = Icon.FromHandle(lParam); + } + else + { + IntPtr icon_handle = Functions.DefWindowProc(handle, message, wParam, lParam); + if (icon_handle != IntPtr.Zero) + icon = Icon.FromHandle(icon_handle); + return icon_handle; + } + + break; + + case WindowMessage.CLOSE: + System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs(); + + if (Closing != null) + Closing(this, e); + + if (!e.Cancel) + { + if (Unload != null) + Unload(this, EventArgs.Empty); + + DestroyWindow(); + break; + } + + return IntPtr.Zero; + + case WindowMessage.DESTROY: + exists = false; + + Functions.UnregisterClass(ClassName, Instance); + //Marshal.FreeHGlobal(ClassName); + window.Dispose(); + child_window.Dispose(); + + if (Closed != null) + Closed(this, EventArgs.Empty); + + break; + + #endregion } - //DefWndProc(ref m); - base.WndProc(ref m); + return Functions.DefWindowProc(handle, message, wParam, lParam); } #endregion - #endregion + #region IsIdle - #region --- INativeGLWindow Members --- - - #region public void ProcessEvents() - - private int ret; - MSG msg; - public void ProcessEvents() - { - while (!IsIdle) - { - ret = Functions.GetMessage(ref msg, Handle, 0, 0); - if (ret == -1) - { - throw new ApplicationException(String.Format( - "An error happened while processing the message queue. Windows error: {0}", - Marshal.GetLastWin32Error())); - } - Functions.DispatchMessage(ref msg); - //WndProc(ref msg); - } - } - - #endregion - - #region public IInputDriver InputDriver - - public IInputDriver InputDriver + bool IsIdle { get { - return driver; + MSG message = new MSG(); + return !Functions.PeekMessage(ref message, window.WindowHandle, 0, 0, 0); } } #endregion - #region public bool Exists + #region CreateWindow + + IntPtr CreateWindow(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device, IntPtr parentHandle) + { + // Use win32 to create the native window. + // Keep in mind that some construction code runs in the WM_CREATE message handler. + + WindowStyle style = + WindowStyle.Visible | + (parentHandle == IntPtr.Zero ? + WindowStyle.OverlappedWindow | WindowStyle.ClipChildren : + WindowStyle.Child | WindowStyle.ClipSiblings); + + ExtendedWindowStyle ex_style = + (parentHandle == IntPtr.Zero ? ParentStyleEx : ChildStyleEx); + + // Find out the final window rectangle, after the WM has added its chrome (titlebar, sidebars etc). + Rectangle rect = new Rectangle(); + rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height; + Functions.AdjustWindowRectEx(ref rect, style, false, ex_style); + + // Create the window class that we will use for this window. + // The current approach is to register a new class for each top-level WinGLWindow we create. + if (!class_registered) + { + ExtendedWindowClass wc = new ExtendedWindowClass(); + wc.Size = ExtendedWindowClass.SizeInBytes; + wc.Style = ClassStyle; + wc.Instance = Instance; + wc.WndProc = WindowProcedureDelegate; + wc.ClassName = ClassName; + //wc.Background = Functions.GetStockObject(5); + ushort atom = Functions.RegisterClassEx(ref wc); + + if (atom == 0) + throw new PlatformException(String.Format("Failed to register window class. Error: {0}", Marshal.GetLastWin32Error())); + + class_registered = true; + } + + IntPtr window_name = Marshal.StringToHGlobalAuto(title); + IntPtr handle = Functions.CreateWindowEx( + ex_style, ClassName, window_name, style, + rect.left, rect.top, rect.Width, rect.Height, + parentHandle, IntPtr.Zero, Instance, IntPtr.Zero); + + if (handle == IntPtr.Zero) + throw new PlatformException(String.Format("Failed to create window. Error: {0}", Marshal.GetLastWin32Error())); + + return handle; + } + + #endregion + + #region DestroyWindow /// - /// Returns true if a render window/context exists. + /// Starts the teardown sequence for the current window. /// - public bool Exists + void DestroyWindow() { - get { return exists; } - } - - #endregion - - #region public bool IsExiting - - public bool IsExiting - { - get { return isExiting; } - } - - #endregion - - #region public bool IsIdle - - public bool IsIdle - { - get + if (Exists) { - //return !API.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); - return !Functions.PeekMessage(ref myGoodMsg, this.Handle, 0, 0, 0); - //return API.GetQueueStatus(API.QueueStatusFlags.ALLEVENTS) == 0; + Debug.Print("Destroying window: {0}", window.ToString()); + Functions.DestroyWindow(window.WindowHandle); + exists = false; } } #endregion - #region public string Text + #endregion + #region INativeWindow Members + + #region Bounds + + public System.Drawing.Rectangle Bounds + { + get { return bounds; } + set + { + // Note: the bounds variable is updated when the resize/move message arrives. + Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, value.X, value.Y, value.Width, value.Height, 0); + } + } + + #endregion + + #region Location + + public Point Location + { + get { return Bounds.Location; } + set + { + // Note: the bounds variable is updated when the resize/move message arrives. + Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, value.X, value.Y, 0, 0, SetWindowPosFlags.NOSIZE); + } + } + + #endregion + + #region Size + + public Size Size + { + get { return Bounds.Size; } + set + { + // Note: the bounds variable is updated when the resize/move message arrives. + Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, 0, 0, value.Width, value.Height, SetWindowPosFlags.NOMOVE); + } + } + + #endregion + + #region ClientRectangle + + public System.Drawing.Rectangle ClientRectangle + { + get + { + if (client_rectangle.Width == 0) + client_rectangle.Width = 1; + if (client_rectangle.Height == 0) + client_rectangle.Height = 1; + return client_rectangle; + } + set + { + Size = value.Size; + } + } + + #endregion + + #region ClientSize + + public Size ClientSize + { + get + { + return ClientRectangle.Size; + } + set + { + WindowStyle style = (WindowStyle)Functions.GetWindowLong(window.WindowHandle, GetWindowLongOffsets.STYLE); + Rectangle rect = Rectangle.From(value); + Functions.AdjustWindowRect(ref rect, style, false); + Size = new Size(rect.Width, rect.Height); + } + } + + #endregion + + #region Width + + public int Width + { + get { return ClientRectangle.Width; } + set { ClientRectangle = new System.Drawing.Rectangle(Location, new Size(value, Height)); } + } + + #endregion + + #region Height + + public int Height + { + get { return ClientRectangle.Height; } + set { ClientRectangle = new System.Drawing.Rectangle(Location, new Size(Width, value)); } + } + + #endregion + + #region X + + public int X + { + get { return ClientRectangle.X; } + set { ClientRectangle = new System.Drawing.Rectangle(new Point(value, Y), Size); } + } + + #endregion + + #region Y + + public int Y + { + get { return ClientRectangle.Y; } + set { ClientRectangle = new System.Drawing.Rectangle(new Point(X, value), Size); } + } + + #endregion + + #region Icon + + public Icon Icon + { + get + { + return icon; + } + set + { + Functions.SendMessage(window.WindowHandle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle); + icon = value; + } + } + + #endregion + + #region Focused + + public bool Focused + { + get + { + IntPtr focus = Functions.GetFocus(); + return + (window != null && focus == window.WindowHandle) || + (child_window != null && focus == child_window.WindowHandle); + } + } + + #endregion + + #region Title + + StringBuilder sb_title = new StringBuilder(256); public string Title { get { - StringBuilder title = new StringBuilder(256); - Functions.GetWindowText(window.WindowHandle, title, title.Capacity); - return title.ToString(); + sb_title.Remove(0, sb_title.Length); + Functions.GetWindowText(window.WindowHandle, sb_title, sb_title.MaxCapacity); + return sb_title.ToString(); } set { -#if DEBUG bool ret = Functions.SetWindowText(window.WindowHandle, value); + if (ret) - Debug.Print("Window {0} title changed to {1}.", window.WindowHandle, value); + Debug.Print("Window {0} title changed to '{1}'.", window.WindowHandle, Title); else - Debug.Print("Window {0} title failed to change to {1}.", window.WindowHandle, value); -#else - Functions.SetWindowText(window.WindowHandle, value); -#endif + Debug.Print("Window {0} title failed to change to '{1}'.", window.WindowHandle, Title); } } #endregion - #region public bool Visible + #region Visible /// /// TODO @@ -286,12 +722,12 @@ namespace OpenTK.Platform.Windows { if (value && !Visible) { - Functions.ShowWindow(Handle, ShowWindowCommand.SHOWNORMAL); + Functions.ShowWindow(window.WindowHandle, ShowWindowCommand.SHOWNORMAL); visible = true; } else if (!value && Visible) { - Functions.ShowWindow(Handle, ShowWindowCommand.HIDE); + Functions.ShowWindow(window.WindowHandle, ShowWindowCommand.HIDE); visible = false; } } @@ -299,161 +735,17 @@ namespace OpenTK.Platform.Windows #endregion - #region public IWindowInfo WindowInfo + #region Exists - public IWindowInfo WindowInfo - { - get { return window; } - //private set { window = value as WindowInfo; } - } + public bool Exists { get { return exists; } } #endregion - #region public void CreateWindow(int width, int height, GraphicsMode mode, out IGraphicsContext context) + #region Close - public void CreateWindow(int width, int height, GraphicsMode mode, int major, int minor, GraphicsContextFlags flags, out IGraphicsContext context) + public void Close() { - Debug.Print("Creating native window."); - Debug.Indent(); - //Debug.Print("GraphicsMode: {0}", format.ToString()); - - CreateParams cp = new CreateParams(); - cp.ClassStyle = - (int)WindowClassStyle.OwnDC | - (int)WindowClassStyle.VRedraw | - (int)WindowClassStyle.HRedraw | - (int)WindowClassStyle.Ime; - cp.Style = - (int)WindowStyle.Visible | - (int)WindowStyle.ClipChildren | - (int)WindowStyle.ClipSiblings | - (int)WindowStyle.OverlappedWindow; - - Rectangle rect = new Rectangle(); - rect.top = rect.left = 0; - rect.bottom = height; - rect.right = width; - Functions.AdjustWindowRect(ref rect, WindowStyle.OverlappedWindow, false); - - // Not used - Top = 0; - Left = 0; - Right = width; - Bottom = height; - // -------- - - top_border = -rect.top; - left_border = -rect.left; - bottom_border = rect.bottom - height; - right_border = rect.right - width; - - //cp.Width = rect.right - rect.left; - //cp.Height = rect.bottom - rect.top; - //cp.Caption = "OpenTK Game Window"; - - // Keep in mind that some construction code runs in WM_CREATE, - // which is raised CreateHandle() - CreateHandle(cp); - - if (this.Handle != IntPtr.Zero) - { - Debug.WriteLine("Window creation succesful."); - //context.Info = new OpenTK.Platform.WindowInfo(this); - //context.CreateContext(); - //Debug.WriteLine("Context creation successful."); - exists = true; - } - else throw new ApplicationException(String.Format( - "Could not create native window and/or context. Handle: {0}", - this.Handle)); - - Functions.SetWindowPos(this.Handle, IntPtr.Zero, Left, Top, rect.right - rect.left, - rect.bottom - rect.top, SetWindowPosFlags.SHOWWINDOW); - - context = new GraphicsContext(mode, window, major, minor, flags); - - Cursor.Current = Cursors.Default; - - Debug.Unindent(); - } - - #endregion - - #region OnCreate - - public event CreateEvent Create; - - public void OnCreate(EventArgs e) - { - this.window = new WinWindowInfo(Handle, null); - - //driver = new WinRawInput(this.window); // Disabled until the mouse issues are resolved. - driver = new WMInput(this.window); - - Debug.Print("Window created: {0}", window); - - if (this.Create != null) - this.Create(this, e); - } - - #endregion - - #region private void DestroyWindow() - - /// - /// Starts the teardown sequence for the current window. - /// - public void DestroyWindow() - { - Debug.Print("Destroying window: {0}", window.ToString()); - //Functions.PostMessage(this.Handle, WindowMessage.DESTROY, IntPtr.Zero, IntPtr.Zero); - Functions.DestroyWindow(this.Handle); - } - - #endregion - - #region OnDestroy - - public void OnDestroy(EventArgs e) - { - Debug.Print("Destroy event fired from window: {0}", window.ToString()); - if (this.Destroy != null) - this.Destroy(this, e); - /* - if (this.Handle != IntPtr.Zero) - { - Debug.Print("Window handle {0} destroyed.", this.Handle); - //this.DestroyHandle(); // Destroyed automatically by DefWndProc - //this.Dispose(); - exists = false; - } - */ - //API.PostQuitMessage(0); - } - - public event DestroyEvent Destroy; - - #endregion - - #region PointToClient - - public Point PointToClient(Point point) - { - if (!Functions.ScreenToClient(this.Handle, ref point)) - throw new InvalidOperationException(String.Format( - "Could not convert point {0} from client to screen coordinates. Windows error: {1}", - point.ToString(), Marshal.GetLastWin32Error())); - - return point; - } - - #endregion - - #region PointToScreen - - public Point PointToScreen(Point p) - { - throw new NotImplementedException(); + DestroyWindow(); } #endregion @@ -464,67 +756,56 @@ namespace OpenTK.Platform.Windows { get { - return windowState; + return windowState; } set { if (WindowState == value) return; - IntPtr style = Functions.GetWindowLong(Handle, GetWindowLongOffsets.STYLE); - ShowWindowCommand command = (ShowWindowCommand)0; - SetWindowPosFlags flags = SetWindowPosFlags.NOREPOSITION; - int new_width = 0, new_height = 0; + ShowWindowCommand command = 0; switch (value) { case WindowState.Normal: command = ShowWindowCommand.RESTORE; - flags |= SetWindowPosFlags.SHOWWINDOW | SetWindowPosFlags.FRAMECHANGED; - - if (WindowState == WindowState.Fullscreen || WindowState == WindowState.Maximized) + if (WindowBorder == WindowBorder.Hidden && previous_window_border != WindowBorder.Hidden) WindowBorder = previous_window_border; - - new_width = previous_client_area.Width; - new_height = previous_client_area.Height; - break; - - case WindowState.Minimized: - command = ShowWindowCommand.SHOWMINIMIZED; - flags |= SetWindowPosFlags.NOSIZE; break; case WindowState.Maximized: + command = ShowWindowCommand.MAXIMIZE; + if (WindowBorder == WindowBorder.Hidden && previous_window_border != WindowBorder.Hidden) + WindowBorder = previous_window_border; + break; + + case WindowState.Minimized: + command = ShowWindowCommand.MINIMIZE; + break; + case WindowState.Fullscreen: - if (WindowState == WindowState.Normal || WindowState == WindowState.Minimized) - { - // Get the normal size of the window, so we can set it when reverting from fullscreen/maximized to normal. - previous_client_area = new Rectangle(window_size.Width, window_size.Height); - previous_window_border = WindowBorder; - } - - command = ShowWindowCommand.SHOWMAXIMIZED; - flags |= SetWindowPosFlags.SHOWWINDOW | SetWindowPosFlags.DRAWFRAME | SetWindowPosFlags.NOSIZE; - - if (value == WindowState.Fullscreen) - this.WindowBorder = WindowBorder.Hidden; - else - this.WindowBorder = previous_window_border; - + // We achieve fullscreen by hiding the window border and maximizing the window. + // We have to 'trick' maximize above to not restore the border, by making it think + // previous_window_border == Hidden. + // After the trick, we store the 'real' previous border, to allow state changes to work + // as expected. + WindowBorder temp = WindowBorder; + previous_window_border = WindowBorder.Hidden; + WindowBorder = WindowBorder.Hidden; + WindowState = WindowState.Maximized; + previous_window_border = temp; break; } - Functions.ShowWindow(Handle, command); - Functions.SetWindowPos(Handle, IntPtr.Zero, 0, 0, new_width, new_height, flags); - - //windowState = value; + if (command != 0) + Functions.ShowWindow(window.WindowHandle, command); } } #endregion #region public WindowBorder WindowBorder - + public WindowBorder WindowBorder { get @@ -545,8 +826,8 @@ namespace OpenTK.Platform.Windows break; case WindowBorder.Fixed: - style |= WindowStyle.OverlappedWindow & ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox | - WindowStyle.SizeBox); + style |= WindowStyle.OverlappedWindow & + ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox | WindowStyle.SizeBox); break; case WindowBorder.Hidden: @@ -554,157 +835,208 @@ namespace OpenTK.Platform.Windows break; } - Functions.SetWindowLong(Handle, GetWindowLongOffsets.STYLE, (IntPtr)(int)style); - Functions.SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0, - SetWindowPosFlags.NOMOVE | SetWindowPosFlags.NOSIZE | SetWindowPosFlags.NOZORDER | SetWindowPosFlags.NOACTIVATE | - SetWindowPosFlags.FRAMECHANGED | SetWindowPosFlags.SHOWWINDOW | SetWindowPosFlags.DRAWFRAME); + // Make sure client size doesn't change when changing the border style. + Size client_size = ClientSize; + Rectangle rect = Rectangle.From(client_size); + Functions.AdjustWindowRectEx(ref rect, style, false, ParentStyleEx); - //windowBorder = value; + // This avoids leaving garbage on the background window. + Visible = false; + + Functions.SetWindowLong(window.WindowHandle, GetWindowLongOffsets.STYLE, (IntPtr)(int)style); + Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, 0, 0, rect.Width, rect.Height, + SetWindowPosFlags.NOMOVE | SetWindowPosFlags.NOZORDER | + SetWindowPosFlags.FRAMECHANGED); + + Visible = true; } } #endregion + #region PointToClient + + public Point PointToClient(Point point) + { + if (!Functions.ScreenToClient(window.WindowHandle, ref point)) + throw new InvalidOperationException(String.Format( + "Could not convert point {0} from client to screen coordinates. Windows error: {1}", + point.ToString(), Marshal.GetLastWin32Error())); + + return point; + } + #endregion - #region --- IResizable Members --- + #region PointToScreen - #region public int Width - - /// Gets a System.Int32 containing the Width of this GameWindow. - public int Width + public Point PointToScreen(Point p) { - get + throw new NotImplementedException(); + } + + #endregion + + #region Events + + public event EventHandler Idle; + + public event EventHandler Load; + + public event EventHandler Unload; + + public event EventHandler Move; + + public event EventHandler Resize; + + public event EventHandler Closing; + + public event EventHandler Closed; + + public event EventHandler Disposed; + + public event EventHandler IconChanged; + + public event EventHandler TitleChanged; + + public event EventHandler ClientSizeChanged; + + public event EventHandler VisibleChanged; + + public event EventHandler WindowInfoChanged; + + public event EventHandler FocusedChanged; + + #endregion + + #endregion + + #region INativeGLWindow Members + + #region public void ProcessEvents() + + private int ret; + MSG msg; + public void ProcessEvents() + { + while (!IsIdle) { - return client_rectangle.Width; - } - set - { - if (value <= 0) throw new ArgumentOutOfRangeException("Window width must be higher than zero."); - //if (WindowState == WindowState.Fullscreen || WindowState == WindowState.Maximized) - // throw new InvalidOperationException("Cannot resize a fullscreen or maximized window."); - Functions.SetWindowPos(Handle, IntPtr.Zero, 0, 0, value, Height, SetWindowPosFlags.NOMOVE); + ret = Functions.GetMessage(ref msg, window.WindowHandle, 0, 0); + if (ret == -1) + { + throw new PlatformException(String.Format( + "An error happened while processing the message queue. Windows error: {0}", + Marshal.GetLastWin32Error())); + } + + Functions.TranslateMessage(ref msg); + Functions.DispatchMessage(ref msg); } } #endregion - #region public int Height + #region public IInputDriver InputDriver - /// Gets a System.Int32 containing the Heights of this GameWindow. - public int Height + public IInputDriver InputDriver { - get - { - return client_rectangle.Height; - } - set - { - if (value <= 0) throw new ArgumentOutOfRangeException("Window height must be higher than zero."); - Functions.SetWindowPos(Handle, IntPtr.Zero, 0, 0, Width, value, SetWindowPosFlags.NOMOVE); - } + get { return this; } } #endregion - #region public void OnResize + #region public IWindowInfo WindowInfo - public event ResizeEvent Resize; - - public void OnResize(ResizeEventArgs e) + public IWindowInfo WindowInfo { - if (Resize != null) - Resize(this, e); - - throw new NotImplementedException("Use GameWindow.OnResize instead."); - //this.width = e.Width; - //this.height = e.Height; - //if (this.Resize != null) - // this.Resize(this, e); + get { return child_window; } } #endregion - #region Top, Bottom, Left and Right + #region OnDestroy - public int Top + public void OnDestroy(EventArgs e) { - get { return top; } - private set { top = value; } + Debug.Print("Destroy event fired from window: {0}", window.ToString()); + + if (this.Destroy != null) + this.Destroy(this, e); } - public int Bottom - { - get { return bottom; } - private set { bottom = value; } - } - - public int Left - { - get { return left; } - private set { left = value; } - } - - public int Right - { - get { return right; } - private set { right = value; } - } + public event DestroyEvent Destroy; #endregion #endregion - #region --- IDisposable Members --- + #region IInputDriver Members + + public void Poll() + { + joystick_driver.Poll(); + } + + #endregion + + #region IKeyboardDriver Members + + public IList Keyboard + { + get { return keyboards; } + } + + #endregion + + #region IMouseDriver Members + + public IList Mouse + { + get { return mice; } + } + + #endregion + + #region IJoystickDriver Members + + public IList Joysticks + { + get { return joystick_driver.Joysticks; } + } + + #endregion + + #region IDisposable Members public void Dispose() { this.Dispose(true); - //GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } - private void Dispose(bool calledManually) + void Dispose(bool calledManually) { if (!disposed) { - // Clean unmanaged resources here: - if (calledManually) { // Safe to clean managed resources - //base.DestroyHandle(); + DestroyWindow(); } + else + { + Debug.Print("[Warning] INativeWindow leaked ({0}). Did you forget to call INativeWindow.Dispose()?", this); + } + disposed = true; } } - /* + ~WinGLNative() { Dispose(false); } - */ + #endregion } - - #region class WindowHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid - - /* - class WindowHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid - { - protected override bool ReleaseHandle() - { - throw new Exception("The method or operation is not implemented."); - } - - public override bool IsInvalid - { - get - { - return base.IsInvalid; - } - } - } - */ - - #endregion } diff --git a/Source/OpenTK/Platform/Windows/WinWindowInfo.cs b/Source/OpenTK/Platform/Windows/WinWindowInfo.cs index b192cb8d..e2e350e1 100644 --- a/Source/OpenTK/Platform/Windows/WinWindowInfo.cs +++ b/Source/OpenTK/Platform/Windows/WinWindowInfo.cs @@ -37,6 +37,7 @@ namespace OpenTK.Platform.Windows { if (dc == IntPtr.Zero) dc = Functions.GetDC(this.WindowHandle); + //dc = Functions.GetWindowDC(this.WindowHandle); return dc; } //set { dc = value; } diff --git a/Source/OpenTK/Platform/X11/Functions.cs b/Source/OpenTK/Platform/X11/Functions.cs index 814d6162..e9ab4a84 100644 --- a/Source/OpenTK/Platform/X11/Functions.cs +++ b/Source/OpenTK/Platform/X11/Functions.cs @@ -124,9 +124,14 @@ namespace OpenTK.Platform.X11 [DllImport("libX11", EntryPoint = "XReparentWindow")] public extern static int XReparentWindow(IntPtr display, IntPtr window, IntPtr parent, int x, int y); + [DllImport("libX11", EntryPoint = "XMoveResizeWindow")] public extern static int XMoveResizeWindow(IntPtr display, IntPtr window, int x, int y, int width, int height); + + [DllImport("libX11", EntryPoint = "XResizeWindow")] + public extern static int XMoveWindow(IntPtr display, IntPtr w, int x, int y); + [DllImport("libX11", EntryPoint = "XResizeWindow")] public extern static int XResizeWindow(IntPtr display, IntPtr window, int width, int height); diff --git a/Source/OpenTK/Platform/X11/X11Factory.cs b/Source/OpenTK/Platform/X11/X11Factory.cs index a17ef392..0cd1b52b 100644 --- a/Source/OpenTK/Platform/X11/X11Factory.cs +++ b/Source/OpenTK/Platform/X11/X11Factory.cs @@ -10,9 +10,9 @@ namespace OpenTK.Platform.X11 { #region IPlatformFactory Members - public INativeGLWindow CreateGLNative() + public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) { - return new X11GLNative(); + return new X11GLNative(x, y, width, height, title, mode, options, device); } public IGLControl CreateGLControl(GraphicsMode mode, GLControl owner) diff --git a/Source/OpenTK/Platform/X11/X11GLContext.cs b/Source/OpenTK/Platform/X11/X11GLContext.cs index 399768d4..c8f9087d 100644 --- a/Source/OpenTK/Platform/X11/X11GLContext.cs +++ b/Source/OpenTK/Platform/X11/X11GLContext.cs @@ -201,21 +201,28 @@ namespace OpenTK.Platform.X11 public void MakeCurrent(IWindowInfo window) { - X11WindowInfo w = (X11WindowInfo)window; - bool result; - - Debug.Write(String.Format("Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... ", - context, System.Threading.Thread.CurrentThread.ManagedThreadId, w.Display, w.Screen, w.WindowHandle)); - - if (w.Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || context == ContextHandle.Zero) - throw new InvalidOperationException("Invalid display, window or context."); - - result = Glx.MakeCurrent(w.Display, w.WindowHandle, context); - - if (!result) - throw new GraphicsContextException("Failed to make context current."); + if (window == null) + { + Glx.MakeCurrent(currentWindow.Display, IntPtr.Zero, IntPtr.Zero); + } else - Debug.WriteLine("done!"); + { + X11WindowInfo w = (X11WindowInfo)window; + bool result; + + Debug.Write(String.Format("Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... ", + context, System.Threading.Thread.CurrentThread.ManagedThreadId, w.Display, w.Screen, w.WindowHandle)); + + if (w.Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || context == ContextHandle.Zero) + throw new InvalidOperationException("Invalid display, window or context."); + + result = Glx.MakeCurrent(w.Display, w.WindowHandle, context); + + if (!result) + throw new GraphicsContextException("Failed to make context current."); + else + Debug.WriteLine("done!"); + } } #endregion @@ -366,24 +373,20 @@ namespace OpenTK.Platform.X11 { if (!disposed) { - // Clean unmanaged resources: - try - { - Functions.XLockDisplay(currentWindow.Display); - Glx.MakeCurrent(currentWindow.Display, IntPtr.Zero, IntPtr.Zero); - Glx.DestroyContext(currentWindow.Display, context); - //Functions.XFree(visual); - } - finally - { - Functions.XUnlockDisplay(currentWindow.Display); - } - if (manuallyCalled) { + if (GraphicsContext.CurrentContext != null && + ((IGraphicsContextInternal)GraphicsContext.CurrentContext).Context == context) + GraphicsContext.CurrentContext.MakeCurrent(null); + + Glx.DestroyContext(currentWindow.Display, context); } + else + { + Debug.Print("[Warning] {0} leaked.", this.GetType().Name); + } + disposed = true; } - disposed = true; } ~X11GLContext() diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 237e8059..00c99692 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -1,24 +1,40 @@ -#region --- License --- -/* Licensed under the MIT/X11 license. - * Copyright (c) 2006-2008 the OpenTK Team. - * This notice may not be removed from any source distribution. - * See license.txt for licensing detailed licensing details. - */ +#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.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; +using System.ComponentModel; using System.Diagnostics; -using System.Reflection; -using OpenTK.Graphics.OpenGL; -using OpenTK.Input; -using OpenTK.Platform.Windows; -using OpenTK.Graphics; using System.Drawing; - -//using OpenTK.Graphics.OpenGL; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using OpenTK.Graphics; +using OpenTK.Input; namespace OpenTK.Platform.X11 { @@ -26,14 +42,13 @@ namespace OpenTK.Platform.X11 /// Drives GameWindow on X11. /// This class supports OpenTK, and is not intended for use by OpenTK programs. /// - internal sealed class X11GLNative : INativeGLWindow, IDisposable + internal sealed class X11GLNative : INativeWindow, IDisposable { // TODO: Disable screensaver. // TODO: What happens if we can't disable decorations through motif? // TODO: Mouse/keyboard grabbing/wrapping. - // TODO: PointToWindow, PointToScreen - #region --- Fields --- + #region Fields const int _min_width = 30, _min_height = 30; @@ -47,6 +62,7 @@ namespace OpenTK.Platform.X11 const string KDE_WM_ATOM = "KWM_WIN_DECORATION"; const string KDE_NET_WM_ATOM = "_KDE_NET_WM_WINDOW_TYPE"; const string ICCM_WM_ATOM = "_NET_WM_WINDOW_TYPE"; + const string ICON_NET_ATOM = "_NET_WM_ICON"; // The Atom class from Mono might be useful to avoid calling XInternAtom by hand (somewhat error prone). IntPtr _atom_wm_destroy; @@ -61,6 +77,10 @@ namespace OpenTK.Platform.X11 IntPtr _atom_net_wm_action_resize; IntPtr _atom_net_wm_action_maximize_horizontally; IntPtr _atom_net_wm_action_maximize_vertically; + + IntPtr _atom_net_wm_icon; + + readonly IntPtr _atom_xa_cardinal = new IntPtr(6); //IntPtr _atom_motif_wm_hints; //IntPtr _atom_kde_wm_hints; @@ -70,14 +90,11 @@ namespace OpenTK.Platform.X11 static readonly IntPtr _atom_add = (IntPtr)1; static readonly IntPtr _atom_toggle = (IntPtr)2; - // Number of pending events. - //int pending = 0; - - int width, height; - int top, bottom, left, right; - - // C# ResizeEventArgs - ResizeEventArgs resizeEventArgs = new ResizeEventArgs(); + Rectangle bounds, client_rectangle; + int border_width; + Icon icon; + bool has_focus; + bool visible; // Used for event loop. XEvent e = new XEvent(); @@ -86,22 +103,80 @@ namespace OpenTK.Platform.X11 bool exists; bool isExiting; - // XAtoms for window properties - //static IntPtr WMTitle; // The title of the GameWindow. - //static IntPtr UTF8String; // No idea. - - // Fields used for fullscreen mode changes. - //int pre_fullscreen_width, pre_fullscreen_height; - //bool fullscreen = false; - bool _decorations_hidden = false; - //OpenTK.WindowState _window_state, _previous_window_state; - //OpenTK.WindowBorder _window_border, _previous_window_border; - #endregion - #region --- Constructors --- + #region Constructors + + public X11GLNative(int x, int y, int width, int height, string title, + GraphicsMode mode,GameWindowFlags options, DisplayDevice device) + : this() + { + if (width <= 0) + throw new ArgumentOutOfRangeException("width", "Must be higher than zero."); + if (height <= 0) + throw new ArgumentOutOfRangeException("height", "Must be higher than zero."); + + XVisualInfo info = new XVisualInfo(); + + Debug.Indent(); + + lock (API.Lock) + { + info.visualid = mode.Index; + int dummy; + window.VisualInfo = (XVisualInfo)Marshal.PtrToStructure( + Functions.XGetVisualInfo(window.Display, XVisualInfoMask.ID, ref info, out dummy), typeof(XVisualInfo)); + + // Create a window on this display using the visual above + Debug.Write("Opening render window... "); + + XSetWindowAttributes attributes = new XSetWindowAttributes(); + attributes.background_pixel = IntPtr.Zero; + attributes.border_pixel = IntPtr.Zero; + attributes.colormap = Functions.XCreateColormap(window.Display, window.RootWindow, window.VisualInfo.visual, 0/*AllocNone*/); + window.EventMask = EventMask.StructureNotifyMask | EventMask.SubstructureNotifyMask | EventMask.ExposureMask | + EventMask.KeyReleaseMask | EventMask.KeyPressMask | + EventMask.PointerMotionMask | EventMask.FocusChangeMask | + EventMask.ButtonPressMask | EventMask.ButtonReleaseMask; + attributes.event_mask = (IntPtr)window.EventMask; + + uint mask = (uint)SetWindowValuemask.ColorMap | (uint)SetWindowValuemask.EventMask | + (uint)SetWindowValuemask.BackPixel | (uint)SetWindowValuemask.BorderPixel; + + window.WindowHandle = Functions.XCreateWindow(window.Display, window.RootWindow, + x, y, width, height, 0, window.VisualInfo.depth/*(int)CreateWindowArgs.CopyFromParent*/, + (int)CreateWindowArgs.InputOutput, window.VisualInfo.visual, (UIntPtr)mask, ref attributes); + + if (window.WindowHandle == IntPtr.Zero) + throw new ApplicationException("XCreateWindow call failed (returned 0)."); + } + + // Set the window hints + SetWindowMinMax(_min_width, _min_height, -1, -1); + + XSizeHints hints = new XSizeHints(); + hints.base_width = width; + hints.base_height = height; + hints.flags = (IntPtr)(XSizeHintsFlags.PSize | XSizeHintsFlags.PPosition); + lock (API.Lock) + { + Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints); + + // Register for window destroy notification + Functions.XSetWMProtocols(window.Display, window.WindowHandle, new IntPtr[] { _atom_wm_destroy }, 1); + + API.MapRaised(window.Display, window.WindowHandle); + } + + driver = new X11Input(window); + + Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle)); + Debug.Unindent(); + + exists = true; + } /// /// Constructs and initializes a new X11GLNative window. @@ -114,18 +189,6 @@ namespace OpenTK.Platform.X11 Debug.Print("Creating X11GLNative window."); Debug.Indent(); - //Utilities.ThrowOnX11Error = true; // Not very reliable - - // We *cannot* reuse the display connection of System.Windows.Forms (Windows.Forms eat our events). - // TODO: Multiple screens. - //Type xplatui = Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms"); - //window.Display = (IntPtr)xplatui.GetField("DisplayHandle", - // System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null); - //window.RootWindow = (IntPtr)xplatui.GetField("RootWindow", - // System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null); - //window.Screen = (int)xplatui.GetField("ScreenNo", - // System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null); - // Open a display connection to the X server, and obtain the screen and root window. window.Display = API.DefaultDisplay; if (window.Display == IntPtr.Zero) @@ -155,6 +218,8 @@ namespace OpenTK.Platform.X11 #endregion + #region Private Members + #region private void RegisterAtoms() /// @@ -182,6 +247,9 @@ namespace OpenTK.Platform.X11 Functions.XInternAtom(window.Display, "_NET_WM_ACTION_MAXIMIZE_HORZ", false); _atom_net_wm_action_maximize_vertically = Functions.XInternAtom(window.Display, "_NET_WM_ACTION_MAXIMIZE_VERT", false); + + _atom_net_wm_icon = + Functions.XInternAtom(window.Display,"_NEW_WM_ICON", false); // string[] atom_names = new string[] // { @@ -198,749 +266,7 @@ namespace OpenTK.Platform.X11 #endregion - #region --- INativeGLWindow Members --- - - #region CreateWindow - - public void CreateWindow(int width, int height, GraphicsMode mode, int major, int minor, GraphicsContextFlags flags, out IGraphicsContext context) - { - if (width <= 0) throw new ArgumentOutOfRangeException("width", "Must be higher than zero."); - if (height <= 0) throw new ArgumentOutOfRangeException("height", "Must be higher than zero."); - if (exists) throw new InvalidOperationException("A render window already exists."); - - XVisualInfo info = new XVisualInfo(); - - Debug.Indent(); - - lock (API.Lock) - { - info.visualid = mode.Index; - int dummy; - window.VisualInfo = (XVisualInfo)Marshal.PtrToStructure( - Functions.XGetVisualInfo(window.Display, XVisualInfoMask.ID, ref info, out dummy), typeof(XVisualInfo)); - - // Create a window on this display using the visual above - Debug.Write("Opening render window... "); - - XSetWindowAttributes attributes = new XSetWindowAttributes(); - attributes.background_pixel = IntPtr.Zero; - attributes.border_pixel = IntPtr.Zero; - attributes.colormap = Functions.XCreateColormap(window.Display, window.RootWindow, window.VisualInfo.visual, 0/*AllocNone*/); - window.EventMask = EventMask.StructureNotifyMask | EventMask.SubstructureNotifyMask | EventMask.ExposureMask | - EventMask.KeyReleaseMask | EventMask.KeyPressMask | - EventMask.PointerMotionMask | // Bad! EventMask.PointerMotionHintMask | - EventMask.ButtonPressMask | EventMask.ButtonReleaseMask; - attributes.event_mask = (IntPtr)window.EventMask; - - uint mask = (uint)SetWindowValuemask.ColorMap | (uint)SetWindowValuemask.EventMask | - (uint)SetWindowValuemask.BackPixel | (uint)SetWindowValuemask.BorderPixel; - - window.WindowHandle = Functions.XCreateWindow(window.Display, window.RootWindow, - 0, 0, width, height, 0, window.VisualInfo.depth/*(int)CreateWindowArgs.CopyFromParent*/, - (int)CreateWindowArgs.InputOutput, window.VisualInfo.visual, (UIntPtr)mask, ref attributes); - - if (window.WindowHandle == IntPtr.Zero) - throw new ApplicationException("XCreateWindow call failed (returned 0)."); - - //XVisualInfo vis = window.VisualInfo; - //Glx.CreateContext(window.Display, ref vis, IntPtr.Zero, true); - } - context = new GraphicsContext(mode, window, major, minor, flags); - - // Set the window hints - SetWindowMinMax(_min_width, _min_height, -1, -1); - - XSizeHints hints = new XSizeHints(); - hints.x = 0; - hints.y = 0; - hints.width = width; - hints.height = height; - hints.flags = (IntPtr)(XSizeHintsFlags.USSize);// | XSizeHintsFlags.USPosition); - lock (API.Lock) - { - Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints); - - // Register for window destroy notification - Functions.XSetWMProtocols(window.Display, window.WindowHandle, new IntPtr[] { _atom_wm_destroy }, 1); - } - Top = Left = 0; - Right = Width; - Bottom = Height; - - //XTextProperty text = new XTextProperty(); - //text.value = "OpenTK Game Window"; - //text.format = 8; - //Functions.XSetWMName(window.Display, window.Handle, ref text); - //Functions.XSetWMProperties(display, window, name, name, 0, /*None*/ null, 0, hints); - - lock (API.Lock) - { - API.MapRaised(window.Display, window.WindowHandle); - } - mapped = true; - - driver = new X11Input(window); - - Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle)); - Debug.Unindent(); - - this.width = width; - this.height = height; - - exists = true; - } - - #endregion - - #region public void ProcessEvents() - - public void ProcessEvents() - { - // Process all pending events - //while (true) - while (Functions.XCheckWindowEvent(window.Display, window.WindowHandle, window.EventMask, ref e) || - Functions.XCheckTypedWindowEvent(window.Display, window.WindowHandle, XEventName.ClientMessage, ref e)) - { - //pending = Functions.XPending(window.Display); - //pending = API.Pending(window.Display); - - //if (pending == 0) - // return; - - //Functions.XNextEvent(window.Display, ref e); - - //Debug.Print("Event: {0} ({1} pending)", e.type, pending); - - // Respond to the event e - switch (e.type) - { - case XEventName.MapNotify: - Debug.WriteLine("Window mapped."); - return; - - case XEventName.CreateNotify: - // A child was was created - nothing to do - break; - - case XEventName.ClientMessage: - if (e.ClientMessageEvent.ptr1 == _atom_wm_destroy) - this.OnDestroy(EventArgs.Empty); - else - Debug.Print("Niar"); - - - break; - - case XEventName.DestroyNotify: - exists = false; - isExiting = true; - Debug.Print("X11 window {0} destroyed.", e.DestroyWindowEvent.window); - window.WindowHandle = IntPtr.Zero; - return; - - case XEventName.ConfigureNotify: - // If the window size changed, raise the C# Resize event. - if (e.ConfigureEvent.width != width || e.ConfigureEvent.height != height) - { - Debug.WriteLine(String.Format("ConfigureNotify: {0}x{1}", e.ConfigureEvent.width, e.ConfigureEvent.height)); - - resizeEventArgs.Width = e.ConfigureEvent.width; - resizeEventArgs.Height = e.ConfigureEvent.height; - this.OnResize(resizeEventArgs); - } - break; - - case XEventName.KeyPress: - case XEventName.KeyRelease: - case XEventName.MotionNotify: - case XEventName.ButtonPress: - case XEventName.ButtonRelease: - //Functions.XPutBackEvent(window.Display, ref e); - driver.ProcessEvent(ref e); - break; - - default: - Debug.WriteLine(String.Format("{0} event was not handled", e.type)); - break; - } - } - } - - #endregion - - #region public IInputDriver InputDriver - - public IInputDriver InputDriver - { - get - { - return driver; - } - } - - #endregion - - #region public bool Exists - - /// - /// Returns true if a render window/context exists. - /// - public bool Exists - { - get { return exists; } - } - - #endregion - - #region public bool Quit - - public bool IsExiting - { - get { return isExiting; } - } - - #endregion - - #region public bool IsIdle - - public bool IsIdle - { - get { throw new Exception("The method or operation is not implemented."); } - } - - #endregion - - #region public bool Fullscreen - - public bool Fullscreen - { - get - { - return false; - //return fullscreen; - } - set - { -// if (value && !fullscreen) -// { -// Debug.Print("Going fullscreen"); -// Debug.Indent(); -// DisableWindowDecorations(); -// pre_fullscreen_height = this.Height; -// pre_fullscreen_width = this.Width; -// //Functions.XRaiseWindow(this.window.Display, this.Handle); -// Functions.XMoveResizeWindow(this.window.Display, this.Handle, 0, 0, -// DisplayDevice.Default.Width, DisplayDevice.Default.Height); -// Debug.Unindent(); -// fullscreen = true; -// } -// else if (!value && fullscreen) -// { -// Debug.Print("Going windowed"); -// Debug.Indent(); -// Functions.XMoveResizeWindow(this.window.Display, this.Handle, 0, 0, -// pre_fullscreen_width, pre_fullscreen_height); -// pre_fullscreen_height = pre_fullscreen_width = 0; -// EnableWindowDecorations(); -// Debug.Unindent(); -// fullscreen = false; -// } - /* - Debug.Print(value ? "Going fullscreen" : "Going windowed"); - IntPtr state_atom = Functions.XInternAtom(this.window.Display, "_NET_WM_STATE", false); - IntPtr fullscreen_atom = Functions.XInternAtom(this.window.Display, "_NET_WM_STATE_FULLSCREEN", false); - XEvent xev = new XEvent(); - xev.ClientMessageEvent.type = XEventName.ClientMessage; - xev.ClientMessageEvent.serial = IntPtr.Zero; - xev.ClientMessageEvent.send_event = true; - xev.ClientMessageEvent.window = this.Handle; - xev.ClientMessageEvent.message_type = state_atom; - xev.ClientMessageEvent.format = 32; - xev.ClientMessageEvent.ptr1 = (IntPtr)(value ? NetWindowManagerState.Add : NetWindowManagerState.Remove); - xev.ClientMessageEvent.ptr2 = (IntPtr)(value ? 1 : 0); - xev.ClientMessageEvent.ptr3 = IntPtr.Zero; - Functions.XSendEvent(this.window.Display, API.RootWindow, false, - (IntPtr)(EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask), ref xev); - - fullscreen = !fullscreen; - */ - } - } - - #endregion - - #region public IntPtr Handle - - /// - /// Gets the current window handle. - /// - public IntPtr Handle - { - get { return this.window.WindowHandle; } - } - - #endregion - - #region public string Title - - /// - /// TODO: Use atoms for this property. - /// Gets or sets the GameWindow title. - /// - public string Title - { - get - { - IntPtr name = IntPtr.Zero; - Functions.XFetchName(window.Display, window.WindowHandle, ref name); - if (name != IntPtr.Zero) - return Marshal.PtrToStringAnsi(name); - - return String.Empty; - } - set - { - /* - XTextProperty name = new XTextProperty(); - name.format = 8; //STRING - if (value == null) - name.value = String.Empty; - else - name.value = value; - - Functions.XSetWMName(window.Display, window.Handle, ref name); - */ - if (value != null) - Functions.XStoreName(window.Display, window.WindowHandle, value); - } - } - - #endregion - - #region public bool Visible - - bool mapped; - public bool Visible - { - get - { - //return true; - return mapped; - } - set - { - if (value && !mapped) - { - Functions.XMapWindow(window.Display, window.WindowHandle); - mapped = true; - } - else if (!value && mapped) - { - Functions.XUnmapWindow(window.Display, window.WindowHandle); - mapped = false; - } - } - } - - #endregion - - #region public IWindowInfo WindowInfo - - public IWindowInfo WindowInfo - { - get { return window; } - } - - #endregion - - #region OnCreate - - public event CreateEvent Create; - - private void OnCreate(EventArgs e) - { - if (this.Create != null) - { - Debug.Print("Create event fired from window: {0}", window.ToString()); - this.Create(this, e); - } - } - - #endregion - - #region public void Exit() - - public void Exit() - { - this.DestroyWindow(); - } - - #endregion - - #region public void DestroyWindow() - - public void DestroyWindow() - { - Debug.WriteLine("X11GLNative shutdown sequence initiated."); - Functions.XDestroyWindow(window.Display, window.WindowHandle); - } - - #endregion - - #region OnDestroy - - public event DestroyEvent Destroy; - - private void OnDestroy(EventArgs e) - { - Debug.Print("Destroy event fired from window: {0}", window.ToString()); - if (this.Destroy != null) - this.Destroy(this, e); - } - - #endregion - - #region PointToClient - - public Point PointToClient(Point point) - { - int ox, oy; - IntPtr child; - - Functions.XTranslateCoordinates(window.Display, window.RootWindow, window.WindowHandle, point.X, point.Y, out ox, out oy, out child); - - point.X = ox; - point.Y = oy; - - return point; - } - - #endregion - - #region PointToScreen - - public Point PointToScreen(Point p) - { - throw new NotImplementedException(); - } - - #endregion - - #region publicOpenTK.WindowState WindowState - - public OpenTK.WindowState WindowState - { - get - { - IntPtr actual_atom; - int actual_format; - IntPtr nitems; - IntPtr bytes_after; - IntPtr prop = IntPtr.Zero; - IntPtr atom; - //XWindowAttributes attributes; - bool fullscreen = false; - int maximized = 0; - bool minimized = false; - - Functions.XGetWindowProperty(window.Display, window.WindowHandle, - _atom_net_wm_state, IntPtr.Zero, new IntPtr (256), false, - IntPtr.Zero, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); - - if ((long)nitems > 0 && prop != IntPtr.Zero) - { - for (int i = 0; i < (long)nitems; i++) - { - atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size); - - if (atom == _atom_net_wm_state_maximized_horizontal || - atom == _atom_net_wm_state_maximized_vertical) - maximized++; - else if (atom == _atom_net_wm_state_minimized) - minimized = true; - else if (atom == _atom_net_wm_state_fullscreen) - fullscreen = true; - } - Functions.XFree(prop); - } - - if (minimized) - return OpenTK.WindowState.Minimized; - else if (maximized == 2) - return OpenTK.WindowState.Maximized; - else if (fullscreen) - return OpenTK.WindowState.Fullscreen; -/* - attributes = new XWindowAttributes(); - Functions.XGetWindowAttributes(window.Display, window.WindowHandle, ref attributes); - if (attributes.map_state == MapState.IsUnmapped) - return (OpenTK.WindowState)(-1); -*/ - return OpenTK.WindowState.Normal; - } - set - { - OpenTK.WindowState current_state = this.WindowState; - - if (current_state == value) - return; - - Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.WindowHandle.ToString(), - current_state.ToString(), value.ToString()); - - if (current_state == OpenTK.WindowState.Minimized) - Functions.XMapWindow(window.Display, window.WindowHandle); - else if (current_state == OpenTK.WindowState.Fullscreen) - Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove, - _atom_net_wm_state_fullscreen, - IntPtr.Zero); - else if (current_state == OpenTK.WindowState.Maximized) - Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle, - _atom_net_wm_state_maximized_horizontal, - _atom_net_wm_state_maximized_vertical); - - Functions.XSync(window.Display, false); - - // We can't resize the window if its border is fixed, so make it resizable first. - bool temporary_resizable = false; - WindowBorder previous_state = WindowBorder; - if (WindowBorder != WindowBorder.Resizable) - { - temporary_resizable = true; - WindowBorder = WindowBorder.Resizable; - } - - switch (value) - { - case OpenTK.WindowState.Normal: - Functions.XRaiseWindow(window.Display, window.WindowHandle); - - break; - - case OpenTK.WindowState.Maximized: - Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, - _atom_net_wm_state_maximized_horizontal, - _atom_net_wm_state_maximized_vertical); - Functions.XRaiseWindow(window.Display, window.WindowHandle); - - break; - - case OpenTK.WindowState.Minimized: - // FIXME multiscreen support - Functions.XIconifyWindow(window.Display, window.WindowHandle, window.Screen); - - break; - - case OpenTK.WindowState.Fullscreen: - //_previous_window_border = this.WindowBorder; - //this.WindowBorder = WindowBorder.Hidden; - Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, - _atom_net_wm_state_fullscreen, IntPtr.Zero); - Functions.XRaiseWindow(window.Display, window.WindowHandle); - - break; - } - - if (temporary_resizable) - WindowBorder = previous_state; - } - } - - #endregion - - #region public OpenTK.WindowBorder WindowBorder - - public OpenTK.WindowBorder WindowBorder - { - get - { - if (IsWindowBorderHidden) - return WindowBorder.Hidden; - - if (IsWindowBorderResizable) - return WindowBorder.Resizable; - else - return WindowBorder.Fixed; - } - set - { - if (WindowBorder == value) - return; - - if (WindowBorder == WindowBorder.Hidden) - EnableWindowDecorations(); - - switch (value) - { - case WindowBorder.Fixed: - Debug.Print("Making WindowBorder fixed."); - SetWindowMinMax((short)Width, (short)Height, (short)Width, (short)Height); - - break; - - case WindowBorder.Resizable: - Debug.Print("Making WindowBorder resizable."); - SetWindowMinMax(_min_width, _min_height, -1, -1); - - break; - - case WindowBorder.Hidden: - Debug.Print("Making WindowBorder hidden."); - DisableWindowDecorations(); - - break; - } - } - } - - #endregion - - #endregion - - #region --- IResizable Members --- - - #region public int Width - - public int Width - { - get - { - return width; - } - set - {/* - // Clear event struct - //Array.Clear(xresize.pad, 0, xresize.pad.Length); - // Set requested parameters - xresize.ResizeRequest.type = EventType.ResizeRequest; - xresize.ResizeRequest.display = this.display; - xresize.ResizeRequest.width = value; - xresize.ResizeRequest.height = mode.Width; - API.SendEvent( - this.display, - this.window, - false, - EventMask.StructureNotifyMask, - ref xresize - );*/ - } - } - - #endregion - - #region public int Height - - public int Height - { - get - { - return height; - } - set - {/* - // Clear event struct - //Array.Clear(xresize.pad, 0, xresize.pad.Length); - // Set requested parameters - xresize.ResizeRequest.type = EventType.ResizeRequest; - xresize.ResizeRequest.display = this.display; - xresize.ResizeRequest.width = mode.Width; - xresize.ResizeRequest.height = value; - API.SendEvent( - this.display, - this.window, - false, - EventMask.StructureNotifyMask, - ref xresize - );*/ - } - } - - #endregion - - #region public event ResizeEvent Resize - - public event ResizeEvent Resize; - - private void OnResize(ResizeEventArgs e) - { - width = e.Width; - height = e.Height; - if (this.Resize != null) - { - this.Resize(this, e); - } - } - - #endregion - - public int Top - { - get { return top; } - private set { top = value; } - } - - public int Bottom - { - get { return bottom; } - private set { bottom = value; } - } - - public int Left - { - get { return left; } - private set { left = value; } - } - - public int Right - { - get { return right; } - private set { right = value; } - } - - #endregion - - #region --- IDisposable Members --- - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool manuallyCalled) - { - if (!disposed) - { - if (window != null && window.WindowHandle != IntPtr.Zero) - { - try - { - Functions.XLockDisplay(window.Display); - Functions.XDestroyWindow(window.Display, window.WindowHandle); - } - finally - { - Functions.XUnlockDisplay(window.Display); - } - - window = null; - } - - if (manuallyCalled) - { - } - disposed = true; - } - } - - ~X11GLNative() - { - this.Dispose(false); - } - - #endregion - - #region --- Private Methods --- + #region SetWindowMinMax void SetWindowMinMax(short min_width, short min_height, short max_width, short max_height) { @@ -977,37 +303,43 @@ namespace OpenTK.Platform.X11 } } + #endregion + + #region IsWindowBorderResizable + bool IsWindowBorderResizable { get { - IntPtr actual_atom; - int actual_format; - IntPtr nitems; - IntPtr bytes_after; - IntPtr prop = IntPtr.Zero; - IntPtr atom; - //XWindowAttributes attributes; + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr atom; + //XWindowAttributes attributes; - Functions.XGetWindowProperty(window.Display, window.WindowHandle, - _atom_net_wm_allowed_actions, IntPtr.Zero, new IntPtr(256), false, - IntPtr.Zero, out actual_atom, out actual_format, out nitems, + Functions.XGetWindowProperty(window.Display, window.WindowHandle, + _atom_net_wm_allowed_actions, IntPtr.Zero, new IntPtr(256), false, + IntPtr.Zero, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); - if ((long)nitems > 0 && prop != IntPtr.Zero) + if ((long)nitems > 0 && prop != IntPtr.Zero) { - for (int i = 0; i < (long)nitems; i++) + for (int i = 0; i < (long)nitems; i++) { atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size); if (atom == _atom_net_wm_action_resize) return true; - } - Functions.XFree(prop); - } + } + Functions.XFree(prop); + } return false; } } + + #endregion #region bool IsWindowBorderHidden @@ -1019,7 +351,7 @@ namespace OpenTK.Platform.X11 //int actual_format; //IntPtr nitems; //IntPtr bytes_after; - IntPtr prop = IntPtr.Zero; + IntPtr prop = IntPtr.Zero; //IntPtr atom; //XWindowAttributes attributes; @@ -1178,5 +510,827 @@ namespace OpenTK.Platform.X11 #endregion #endregion + + #region INativeWindow Members + + #region ProcessEvents + + public void ProcessEvents() + { + // Process all pending events + if (!exists || window == null) + return; + + while (Functions.XCheckWindowEvent(window.Display, window.WindowHandle, window.EventMask, ref e) || + Functions.XCheckTypedWindowEvent(window.Display, window.WindowHandle, XEventName.ClientMessage, ref e)) + { + // Respond to the event e + switch (e.type) + { + case XEventName.MapNotify: + { + bool previous_visible = visible; + visible = true; + if (visible != previous_visible) + if (VisibleChanged != null) + VisibleChanged(this, EventArgs.Empty); + } + return; + + case XEventName.UnmapNotify: + { + bool previous_visible = visible; + visible = false; + if (visible != previous_visible) + if (VisibleChanged != null) + VisibleChanged(this, EventArgs.Empty); + } + break; + + case XEventName.CreateNotify: + // A child was was created - nothing to do + break; + + case XEventName.ClientMessage: + if (e.ClientMessageEvent.ptr1 == _atom_wm_destroy) + { + CancelEventArgs ce = new CancelEventArgs(); + if (Closing != null) + Closing(this, ce); + + if (!ce.Cancel) + { + isExiting = true; + + if (Unload != null) + Unload(this, EventArgs.Empty); + + Functions.XDestroyWindow(window.Display, window.WindowHandle); + break; + } + } + + break; + + case XEventName.DestroyNotify: + exists = false; + + if (Closed != null) + Closed(this, EventArgs.Empty); + + break; + + case XEventName.ConfigureNotify: + border_width = e.ConfigureEvent.border_width; + + Point new_location = new Point(e.ConfigureEvent.x, e.ConfigureEvent.y); + if (Location != new_location) + { + bounds.Location = new_location; + if (Move != null) + Move(this, EventArgs.Empty); + } + + // Note: width and height denote the internal (client) size. + // To get the external (window) size, we need to add the border size. + Size new_size = new Size(e.ConfigureEvent.width, e.ConfigureEvent.height); + if (ClientSize != new_size) + { + bounds.Size = new_size; + bounds.Width += e.ConfigureEvent.border_width; + bounds.Height += e.ConfigureEvent.border_width; + + // Todo: Get the real client rectangle. + client_rectangle.Size = new_size; + + if (this.Resize != null) + Resize(this, EventArgs.Empty); + } + break; + + case XEventName.KeyPress: + case XEventName.KeyRelease: + case XEventName.MotionNotify: + case XEventName.ButtonPress: + case XEventName.ButtonRelease: + //Functions.XPutBackEvent(window.Display, ref e); + driver.ProcessEvent(ref e); + break; + + case XEventName.FocusIn: + { + bool previous_focus = has_focus; + has_focus = true; + if (has_focus != previous_focus) + if (FocusedChanged != null) + FocusedChanged(this, EventArgs.Empty); + } + break; + + case XEventName.FocusOut: + { + bool previous_focus = has_focus; + has_focus = false; + if (has_focus != previous_focus) + if (FocusedChanged != null) + FocusedChanged(this, EventArgs.Empty); + } + break; + + default: + //Debug.WriteLine(String.Format("{0} event was not handled", e.type)); + break; + } + } + } + + #endregion + + #region Bounds + + public System.Drawing.Rectangle Bounds + { + get { return bounds; } + set + { + Functions.XMoveResizeWindow(window.Display, window.WindowHandle, + value.X, value.Y, value.Width - border_width, value.Height - border_width); + } + } + + #endregion + + #region Location + + public Point Location + { + get { return Bounds.Location; } + set + { + Functions.XMoveWindow(window.Display, window.WindowHandle, value.X, value.Y); + } + } + + #endregion + + #region Size + + public Size Size + { + get { return Bounds.Size; } + set + { + int width = value.Width - border_width; + int height = value.Height - border_width; + width = width < 0 ? 1 : width; + height = height < 0 ? 1 : height; + + Functions.XResizeWindow(window.Display, window.WindowHandle, width, height); + } + } + + #endregion + + #region ClientRectangle + + public System.Drawing.Rectangle ClientRectangle + { + get + { + if (client_rectangle.Width == 0) + client_rectangle.Width = 1; + if (client_rectangle.Height == 0) + client_rectangle.Height = 1; + return client_rectangle; + } + set + { + Functions.XResizeWindow(window.Display, window.WindowHandle, + value.Width, value.Height); + } + } + + #endregion + + #region ClientSize + + public Size ClientSize + { + get + { + return ClientRectangle.Size; + } + set + { + ClientRectangle = new Rectangle(Point.Empty, value); + } + } + + #endregion + + #region Width + + public int Width + { + get { return Bounds.Width; } + set { Size = new Size(value, Height); } + } + + #endregion + + #region Height + + public int Height + { + get { return Bounds.Height; } + set { Size = new Size(Width, value); } + } + + #endregion + + #region X + + public int X + { + get { return Bounds.X; } + set { Location = new Point(value, Y); } + } + + #endregion + + #region Y + + public int Y + { + get { return Bounds.Y; } + set { Location = new Point(X, value); } + } + + #endregion + + #region Icon + + public Icon Icon + { + get + { + return icon; + } + set + { + if (value == null) + { + Functions.XDeleteProperty(window.Display, window.WindowHandle, _atom_net_wm_icon); + } + else + { + Bitmap bitmap; + int size; + IntPtr[] data; + int index; + + bitmap = icon.ToBitmap(); + index = 0; + size = bitmap.Width * bitmap.Height + 2; + data = new IntPtr[size]; + + data[index++] = (IntPtr)bitmap.Width; + data[index++] = (IntPtr)bitmap.Height; + + for (int y = 0; y < bitmap.Height; y++) + for (int x = 0; x < bitmap.Width; x++) + data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb(); + + Functions.XChangeProperty(window.Display, window.WindowHandle, + _atom_net_wm_icon, _atom_xa_cardinal, 32, + PropertyMode.Replace, data, size); + } + + icon = value; + } + } + + #endregion + + #region Focused + + public bool Focused + { + get + { + return has_focus; + } + } + + #endregion + + #region Events + + public event EventHandler Load; + + public event EventHandler Unload; + + public event EventHandler Move; + + public event EventHandler Resize; + + public event EventHandler Closing; + + public event EventHandler Closed; + + public event EventHandler Disposed; + + public event EventHandler IconChanged; + + public event EventHandler TitleChanged; + + public event EventHandler VisibleChanged; + + public event EventHandler FocusedChanged; + + #endregion + + #endregion + + #region --- INativeGLWindow Members --- + + #region public IInputDriver InputDriver + + public IInputDriver InputDriver + { + get + { + return driver; + } + } + + #endregion + + #region public bool Exists + + /// + /// Returns true if a render window/context exists. + /// + public bool Exists + { + get { return exists; } + } + + #endregion + + #region public bool IsExiting + + public bool IsExiting + { + get { return isExiting; } + } + + #endregion + + #region public bool IsIdle + + public bool IsIdle + { + get { throw new Exception("The method or operation is not implemented."); } + } + + #endregion + + #region public bool Fullscreen + + public bool Fullscreen + { + get + { + return false; + //return fullscreen; + } + set + { +// if (value && !fullscreen) +// { +// Debug.Print("Going fullscreen"); +// Debug.Indent(); +// DisableWindowDecorations(); +// pre_fullscreen_height = this.Height; +// pre_fullscreen_width = this.Width; +// //Functions.XRaiseWindow(this.window.Display, this.Handle); +// Functions.XMoveResizeWindow(this.window.Display, this.Handle, 0, 0, +// DisplayDevice.Default.Width, DisplayDevice.Default.Height); +// Debug.Unindent(); +// fullscreen = true; +// } +// else if (!value && fullscreen) +// { +// Debug.Print("Going windowed"); +// Debug.Indent(); +// Functions.XMoveResizeWindow(this.window.Display, this.Handle, 0, 0, +// pre_fullscreen_width, pre_fullscreen_height); +// pre_fullscreen_height = pre_fullscreen_width = 0; +// EnableWindowDecorations(); +// Debug.Unindent(); +// fullscreen = false; +// } + /* + Debug.Print(value ? "Going fullscreen" : "Going windowed"); + IntPtr state_atom = Functions.XInternAtom(this.window.Display, "_NET_WM_STATE", false); + IntPtr fullscreen_atom = Functions.XInternAtom(this.window.Display, "_NET_WM_STATE_FULLSCREEN", false); + XEvent xev = new XEvent(); + xev.ClientMessageEvent.type = XEventName.ClientMessage; + xev.ClientMessageEvent.serial = IntPtr.Zero; + xev.ClientMessageEvent.send_event = true; + xev.ClientMessageEvent.window = this.Handle; + xev.ClientMessageEvent.message_type = state_atom; + xev.ClientMessageEvent.format = 32; + xev.ClientMessageEvent.ptr1 = (IntPtr)(value ? NetWindowManagerState.Add : NetWindowManagerState.Remove); + xev.ClientMessageEvent.ptr2 = (IntPtr)(value ? 1 : 0); + xev.ClientMessageEvent.ptr3 = IntPtr.Zero; + Functions.XSendEvent(this.window.Display, API.RootWindow, false, + (IntPtr)(EventMask.SubstructureRedirectMask | EventMask.SubstructureNotifyMask), ref xev); + + fullscreen = !fullscreen; + */ + } + } + + #endregion + + #region public IntPtr Handle + + /// + /// Gets the current window handle. + /// + public IntPtr Handle + { + get { return this.window.WindowHandle; } + } + + #endregion + + #region public string Title + + /// + /// TODO: Use atoms for this property. + /// Gets or sets the GameWindow title. + /// + public string Title + { + get + { + IntPtr name = IntPtr.Zero; + Functions.XFetchName(window.Display, window.WindowHandle, ref name); + if (name != IntPtr.Zero) + return Marshal.PtrToStringAnsi(name); + + return String.Empty; + } + set + { + if (value != null) + Functions.XStoreName(window.Display, window.WindowHandle, value); + } + } + + #endregion + + #region public bool Visible + + public bool Visible + { + get + { + return visible; + } + set + { + if (value && !visible) + { + Functions.XMapWindow(window.Display, window.WindowHandle); + } + else if (!value && visible) + { + Functions.XUnmapWindow(window.Display, window.WindowHandle); + } + } + } + + #endregion + + #region public IWindowInfo WindowInfo + + public IWindowInfo WindowInfo + { + get { return window; } + } + + #endregion + + #region OnCreate + + public event CreateEvent Create; + + private void OnCreate(EventArgs e) + { + if (this.Create != null) + { + Debug.Print("Create event fired from window: {0}", window.ToString()); + this.Create(this, e); + } + } + + #endregion + + public void Close() { Exit(); } + + #region public void Exit() + + public void Exit() + { + XEvent ev = new XEvent(); + ev.ClientMessageEvent.ptr1 = _atom_wm_destroy; + Functions.XSendEvent(window.Display, window.WindowHandle, false, + new IntPtr((int)EventMask.NoEventMask), ref ev); + } + + #endregion + + #region public void DestroyWindow() + + public void DestroyWindow() + { + Debug.WriteLine("X11GLNative shutdown sequence initiated."); + Functions.XDestroyWindow(window.Display, window.WindowHandle); + } + + #endregion + + #region OnDestroy + + public event DestroyEvent Destroy; + + private void OnDestroy(EventArgs e) + { + Debug.Print("Destroy event fired from window: {0}", window.ToString()); + if (this.Destroy != null) + this.Destroy(this, e); + } + + #endregion + + #region PointToClient + + public Point PointToClient(Point point) + { + int ox, oy; + IntPtr child; + + Functions.XTranslateCoordinates(window.Display, window.RootWindow, window.WindowHandle, point.X, point.Y, out ox, out oy, out child); + + point.X = ox; + point.Y = oy; + + return point; + } + + #endregion + + #region PointToScreen + + public Point PointToScreen(Point point) + { + int ox, oy; + IntPtr child; + + Functions.XTranslateCoordinates(window.Display, window.WindowHandle, window.RootWindow, point.X, point.Y, out ox, out oy, out child); + + point.X = ox; + point.Y = oy; + + return point; + } + + #endregion + + #region publicOpenTK.WindowState WindowState + + public OpenTK.WindowState WindowState + { + get + { + IntPtr actual_atom; + int actual_format; + IntPtr nitems; + IntPtr bytes_after; + IntPtr prop = IntPtr.Zero; + IntPtr atom; + //XWindowAttributes attributes; + bool fullscreen = false; + int maximized = 0; + bool minimized = false; + + Functions.XGetWindowProperty(window.Display, window.WindowHandle, + _atom_net_wm_state, IntPtr.Zero, new IntPtr (256), false, + IntPtr.Zero, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop); + + if ((long)nitems > 0 && prop != IntPtr.Zero) + { + for (int i = 0; i < (long)nitems; i++) + { + atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size); + + if (atom == _atom_net_wm_state_maximized_horizontal || + atom == _atom_net_wm_state_maximized_vertical) + maximized++; + else if (atom == _atom_net_wm_state_minimized) + minimized = true; + else if (atom == _atom_net_wm_state_fullscreen) + fullscreen = true; + } + Functions.XFree(prop); + } + + if (minimized) + return OpenTK.WindowState.Minimized; + else if (maximized == 2) + return OpenTK.WindowState.Maximized; + else if (fullscreen) + return OpenTK.WindowState.Fullscreen; +/* + attributes = new XWindowAttributes(); + Functions.XGetWindowAttributes(window.Display, window.WindowHandle, ref attributes); + if (attributes.map_state == MapState.IsUnmapped) + return (OpenTK.WindowState)(-1); +*/ + return OpenTK.WindowState.Normal; + } + set + { + OpenTK.WindowState current_state = this.WindowState; + + if (current_state == value) + return; + + Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.WindowHandle.ToString(), + current_state.ToString(), value.ToString()); + + if (current_state == OpenTK.WindowState.Minimized) + Functions.XMapWindow(window.Display, window.WindowHandle); + else if (current_state == OpenTK.WindowState.Fullscreen) + Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove, + _atom_net_wm_state_fullscreen, + IntPtr.Zero); + else if (current_state == OpenTK.WindowState.Maximized) + Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle, + _atom_net_wm_state_maximized_horizontal, + _atom_net_wm_state_maximized_vertical); + + Functions.XSync(window.Display, false); + + // We can't resize the window if its border is fixed, so make it resizable first. + bool temporary_resizable = false; + WindowBorder previous_state = WindowBorder; + if (WindowBorder != WindowBorder.Resizable) + { + temporary_resizable = true; + WindowBorder = WindowBorder.Resizable; + } + + switch (value) + { + case OpenTK.WindowState.Normal: + Functions.XRaiseWindow(window.Display, window.WindowHandle); + + break; + + case OpenTK.WindowState.Maximized: + Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, + _atom_net_wm_state_maximized_horizontal, + _atom_net_wm_state_maximized_vertical); + Functions.XRaiseWindow(window.Display, window.WindowHandle); + + break; + + case OpenTK.WindowState.Minimized: + // Todo: multiscreen support + Functions.XIconifyWindow(window.Display, window.WindowHandle, window.Screen); + + break; + + case OpenTK.WindowState.Fullscreen: + //_previous_window_border = this.WindowBorder; + //this.WindowBorder = WindowBorder.Hidden; + Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, + _atom_net_wm_state_fullscreen, IntPtr.Zero); + Functions.XRaiseWindow(window.Display, window.WindowHandle); + + break; + } + + if (temporary_resizable) + WindowBorder = previous_state; + } + } + + #endregion + + #region public OpenTK.WindowBorder WindowBorder + + public OpenTK.WindowBorder WindowBorder + { + get + { + if (IsWindowBorderHidden) + return WindowBorder.Hidden; + + if (IsWindowBorderResizable) + return WindowBorder.Resizable; + else + return WindowBorder.Fixed; + } + set + { + if (WindowBorder == value) + return; + + if (WindowBorder == WindowBorder.Hidden) + EnableWindowDecorations(); + + switch (value) + { + case WindowBorder.Fixed: + Debug.Print("Making WindowBorder fixed."); + SetWindowMinMax((short)Width, (short)Height, (short)Width, (short)Height); + + break; + + case WindowBorder.Resizable: + Debug.Print("Making WindowBorder resizable."); + SetWindowMinMax(_min_width, _min_height, -1, -1); + + break; + + case WindowBorder.Hidden: + Debug.Print("Making WindowBorder hidden."); + DisableWindowDecorations(); + + break; + } + } + } + + #endregion + + #endregion + + #region IDisposable Members + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manuallyCalled) + { + if (!disposed) + { + if (manuallyCalled) + { + if (window != null && window.WindowHandle != IntPtr.Zero) + { + try + { + Functions.XLockDisplay(window.Display); + Functions.XDestroyWindow(window.Display, window.WindowHandle); + } + finally + { + Functions.XUnlockDisplay(window.Display); + } + + while (Exists) + ProcessEvents(); + + if (GraphicsContext.CurrentContext != null) + GraphicsContext.CurrentContext.MakeCurrent(null); + + window.Dispose(); + window = null; + } + } + else + { + Debug.Print("[Warning] {0} leaked.", this.GetType().Name); + } + disposed = true; + } + } + + ~X11GLNative() + { + this.Dispose(false); + } + + #endregion } } diff --git a/Source/OpenTK/Platform/X11/X11XrandrDisplayDevice.cs b/Source/OpenTK/Platform/X11/X11XrandrDisplayDevice.cs index 3c88fae9..7a08758c 100644 --- a/Source/OpenTK/Platform/X11/X11XrandrDisplayDevice.cs +++ b/Source/OpenTK/Platform/X11/X11XrandrDisplayDevice.cs @@ -38,6 +38,7 @@ namespace OpenTK.Platform.X11 // Get available resolutions. Then, for each resolution get all // available rates. // TODO: Global X11 lock. + // TODO: Use xinerama to get the bounds of each monitor. for (int screen = 0; screen < API.ScreenCount; screen++) { IntPtr timestamp_of_last_update; @@ -63,11 +64,11 @@ namespace OpenTK.Platform.X11 { if (rate != 0) foreach (int depth in depths) - available_res.Add(new DisplayResolution(size.Width, size.Height, depth, (float)rate)); + available_res.Add(new DisplayResolution(0, 0, size.Width, size.Height, depth, (float)rate)); } // Keep the index of this resolution - we will need it for resolution changes later. foreach (int depth in depths) - screenResolutionToIndex[screen].Add(new DisplayResolution(size.Width, size.Height, depth, 0), + screenResolutionToIndex[screen].Add(new DisplayResolution(0, 0, size.Width, size.Height, depth, 0), resolution_count); ++resolution_count; @@ -84,8 +85,10 @@ namespace OpenTK.Platform.X11 int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation); DisplayDevice current_device = new DisplayDevice( - new DisplayResolution(available_res[current_resolution_index].Width, available_res[current_resolution_index].Height, - current_depth, current_refresh_rate), + new DisplayResolution( + 0, 0, + available_res[current_resolution_index].Width, available_res[current_resolution_index].Height, + current_depth, current_refresh_rate), screen == Functions.XDefaultScreen(API.DefaultDisplay), available_res); @@ -162,7 +165,7 @@ namespace OpenTK.Platform.X11 int new_resolution_index; if (resolution != null) new_resolution_index = screenResolutionToIndex[screen] - [new DisplayResolution(resolution.Width, resolution.Height, resolution.BitsPerPixel, 0)]; + [new DisplayResolution(0, 0, resolution.Width, resolution.Height, resolution.BitsPerPixel, 0)]; else new_resolution_index = deviceToDefaultResolution[device];