diff --git a/Source/OpenTK/GameWindow.cs b/Source/OpenTK/GameWindow.cs index d08839fb..5465446d 100644 --- a/Source/OpenTK/GameWindow.cs +++ b/Source/OpenTK/GameWindow.cs @@ -10,6 +10,8 @@ using System.Text; using System.Diagnostics; using OpenTK.Platform; +using OpenTK.Input; +using System.Threading; namespace OpenTK { @@ -23,6 +25,9 @@ namespace OpenTK private InputDriver driver; + private bool isExiting; + private bool disposed; + #endregion #region --- Contructors --- @@ -70,38 +75,10 @@ namespace OpenTK #endregion - #region --- Public Properties --- - - #region public IList Keyboard - - /// - /// Gets the list of available Keyboard devices. - /// - public IList Keyboard - { - get - { - return InputDriver.Keyboard; - } - } - - #endregion + #region --- Internal Properties --- #region public IList Input - /// - /// Gets the list of available InputDevices. - /// - public IList Input - { - get - { - return InputDriver.InputDevices; - } - } - - #endregion - internal InputDriver InputDriver { get @@ -117,6 +94,8 @@ namespace OpenTK #endregion + #endregion + #region --- INativeGLWindow Members --- #region public void CreateWindow(DisplayMode mode) @@ -128,7 +107,7 @@ namespace OpenTK /// Occurs when a render window already exists. public void CreateWindow(DisplayMode mode) { - if (!Created) + if (!Exists) { glWindow.CreateWindow(mode); } @@ -144,10 +123,15 @@ namespace OpenTK /// /// Gracefully exits the current GameWindow. + /// Override if you want to provide yor own exit sequence. + /// If you override this method, place a call to base.Exit(), to ensure + /// proper OpenTK shutdown. /// - public void Exit() + public virtual void Exit() { - glWindow.Exit(); + isExiting = true; + //glWindow.Exit(); + //this.Dispose(); } #endregion @@ -202,7 +186,7 @@ namespace OpenTK { get { - if (!glWindow.Created) + if (!glWindow.Exists) { Debug.WriteLine("WARNING: OpenGL Context accessed before creating a render window. This may indicate a programming error. Force-creating a render window."); mode = new DisplayMode(640, 480); @@ -214,14 +198,14 @@ namespace OpenTK #endregion - #region public bool Created + #region public bool Exists /// - /// Gets a value indicating whether a render window has been created. + /// Gets a value indicating whether a render window has been exists. /// - public bool Created + public bool Exists { - get { return glWindow.Created; } + get { return glWindow.Exists; } } #endregion @@ -258,12 +242,18 @@ namespace OpenTK /// public virtual void Run() { - while (!this.Quit) + while (!this.Quit && !IsExiting) { this.ProcessEvents(); this.OnUpdateFrame(); this.OnRenderFrame(); } + + glWindow.Exit(); + while (glWindow.Exists) + { + this.ProcessEvents(); + } } #endregion @@ -315,7 +305,7 @@ namespace OpenTK /// public virtual void OnRenderFrame() { - if (!this.Created) + if (!this.Exists) { Debug.Print("WARNING: RenderFrame event raised, without a valid render window. This may indicate a programming error. Creating render window."); mode = new DisplayMode(640, 480); @@ -338,7 +328,7 @@ namespace OpenTK /// public virtual void OnUpdateFrame() { - if (!this.Created) + if (!this.Exists) { 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); @@ -360,6 +350,36 @@ namespace OpenTK /// public event RenderFrameEvent RenderFrame; + #region public bool IsExiting + + /// + /// Gets a value indicating whether the shutdown sequence has been initiated + /// for this window, by calling GameWindow.Exit() or hitting the 'close' button. + /// If this property is true, it is no longer safe to use any OpenTK.Input or + /// OpenTK.OpenGL functions or properties. + /// + public bool IsExiting + { + get { return isExiting; } + } + + #endregion + + #region public IList Keyboard + + /// + /// Gets the list of available Keyboard devices. + /// + public IList Keyboard + { + get + { + return InputDriver.Keyboard; + } + } + + #endregion + #endregion #region --- IResizable Members --- @@ -438,8 +458,32 @@ namespace OpenTK public void Dispose() { - glWindow.Dispose(); - glWindow = null; + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool manual) + { + if (!disposed) + { + // Is this safe? Maybe 'Debug' has been disposed, too... + Debug.Print("{0} disposing GameWindow.", manual ? "Manually" : "Automatically"); + + if (manual) + { + if (glWindow != null) + { + glWindow.Dispose(); + glWindow = null; + } + } + disposed = true; + } + } + + ~GameWindow() + { + Dispose(false); } #endregion diff --git a/Source/OpenTK/Input/Keyboard.cs b/Source/OpenTK/Input/Keyboard.cs index bfc9f0df..b9b070c9 100644 --- a/Source/OpenTK/Input/Keyboard.cs +++ b/Source/OpenTK/Input/Keyboard.cs @@ -141,7 +141,7 @@ namespace OpenTK.Input Escape, Space, Tab, - Backspace, + BackSpace, Insert, Delete, PageUp, diff --git a/Source/OpenTK/Platform/IGameWindow.cs b/Source/OpenTK/Platform/IGameWindow.cs index b3c8a6dd..fbf4d917 100644 --- a/Source/OpenTK/Platform/IGameWindow.cs +++ b/Source/OpenTK/Platform/IGameWindow.cs @@ -14,6 +14,9 @@ namespace OpenTK.Platform event UpdateFrameEvent UpdateFrame; event RenderFrameEvent RenderFrame; + + bool IsExiting { get; } + IList Keyboard { get; } } public delegate void UpdateFrameEvent(EventArgs e); diff --git a/Source/OpenTK/Platform/INativeGLWindow.cs b/Source/OpenTK/Platform/INativeGLWindow.cs index a4d07a00..febbb819 100644 --- a/Source/OpenTK/Platform/INativeGLWindow.cs +++ b/Source/OpenTK/Platform/INativeGLWindow.cs @@ -13,7 +13,7 @@ namespace OpenTK.Platform void ProcessEvents(); void Exit(); - bool Created { get; } + bool Exists { get; } bool Quit { get; } IWindowInfo WindowInfo { get; } } diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index dc20cfac..7b3a6ad4 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -31,7 +31,7 @@ namespace OpenTK.Platform.Windows private bool fullscreen = false; private bool disposed; private bool quit; - private bool created; + private bool exists; private WindowInfo info; #endregion @@ -94,27 +94,18 @@ namespace OpenTK.Platform.Windows // Raise the Create event this.OnCreate(EventArgs.Empty); - - // Raise the resize event: - //resizeEventArgs.Width = width; - //resizeEventArgs.Height = height; - //this.OnResize(resizeEventArgs); return; - //case API.Constants.WM_KEYDOWN: // Legacy input events - //case API.Constants.WM_KEYUP: - // break; - case API.Constants.WM_CLOSE: - //this.Exit(); - //return; - break; + this.Exit(); + return; case API.Constants.WM_DESTROY: if (this.Handle != IntPtr.Zero) { Debug.Print("Window handle {0} destroyed.", this.Handle); this.DestroyHandle(); + exists = false; } API.PostQuitMessage(0); return; @@ -174,7 +165,7 @@ namespace OpenTK.Platform.Windows if (this.Handle != IntPtr.Zero && glContext != null) { Debug.WriteLine("Window creation was succesful."); - created = true; + exists = true; } else { @@ -281,14 +272,14 @@ namespace OpenTK.Platform.Windows #endregion - #region public bool Created + #region public bool Exists /// /// Returns true if a render window/context exists. /// - public bool Created + public bool Exists { - get { return created; } + get { return exists; } } #endregion diff --git a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs index 74398dac..ce723f51 100644 --- a/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs +++ b/Source/OpenTK/Platform/Windows/WinRawKeyboard.cs @@ -71,7 +71,7 @@ namespace OpenTK.Platform.Windows KeyMap.Add(API.VirtualKeys.RCONTROL, Input.Key.ControlRight); KeyMap.Add(API.VirtualKeys.RSHIFT, Input.Key.ShiftRight); KeyMap.Add(API.VirtualKeys.RETURN, Input.Key.Enter); - KeyMap.Add(API.VirtualKeys.BACK, Input.Key.Backspace); + KeyMap.Add(API.VirtualKeys.BACK, Input.Key.BackSpace); KeyMap.Add(API.VirtualKeys.OEM_1, Input.Key.Semicolon); // Varies by keyboard, ;: on Win2K/US KeyMap.Add(API.VirtualKeys.OEM_2, Input.Key.Slash); // Varies by keyboard, /? on Win2K/US diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 6b6f2e6c..43605f26 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -103,7 +103,7 @@ namespace OpenTK.Platform.X11 XSetWindowAttributes attributes = new XSetWindowAttributes(); attributes.colormap = glContext.colormap; - attributes.event_mask = (IntPtr)(EventMask.StructureNotifyMask); + attributes.event_mask = (IntPtr)(EventMask.StructureNotifyMask | EventMask.ExposureMask); SetWindowValuemask mask = SetWindowValuemask.ColorMap | SetWindowValuemask.EventMask; @@ -163,13 +163,12 @@ namespace OpenTK.Platform.X11 public void Exit() { - /*Event e = new Event(); - X11Api.SendEvent( - display, - window, - false, - 0,*/ - //quit = true; + Debug.WriteLine("X11GLNative shutdown sequence initiated."); + quit = true; + Functions.XDestroyWindow(window.Display, window.Handle); + window = null; + glContext.Dispose(); + glContext = null; } #endregion @@ -181,7 +180,6 @@ namespace OpenTK.Platform.X11 // Process all pending events while (true) { - //pending = Functions.XPending(info.Display); pending = Functions.XPending(window.Display); if (pending == 0) @@ -201,15 +199,14 @@ namespace OpenTK.Platform.X11 break; case XEventName.CreateNotify: - // A child was created - nothing to do + // A child was exists - nothing to do break; case XEventName.DestroyNotify: - glContext.Dispose(); - Functions.XDestroyWindow(window.Display, window.Handle); - window = null; - glContext = null; - quit = true; + //glContext.Dispose(); + //window = null; + //glContext = null; + //quit = true; Debug.WriteLine("Window destroyed, shutting down."); break; @@ -257,12 +254,12 @@ namespace OpenTK.Platform.X11 #endregion - #region public bool Created + #region public bool Exists /// /// Returns true if a render window/context exists. /// - public bool Created + public bool Exists { get { return created; } } diff --git a/Source/OpenTK/Platform/X11/X11Input.cs b/Source/OpenTK/Platform/X11/X11Input.cs index 52841cd4..9eb14753 100644 --- a/Source/OpenTK/Platform/X11/X11Input.cs +++ b/Source/OpenTK/Platform/X11/X11Input.cs @@ -126,39 +126,8 @@ namespace OpenTK.Platform.X11 { while (API.CheckMaskEvent(window.Display, EventMask.KeyReleaseMask | EventMask.KeyPressMask, ref e)) { - Debug.Print("Input window received {0} event... ", e.type.ToString()); keyboardDriver.ProcessKeyboardEvent(e.KeyEvent); } - /* - try - { - while (API.CheckIfEvent(window.Display, ref e, check, IntPtr.Zero)) - { - Debug.Print("Input window received {0} event... ", e.type.ToString()); - keyboardDriver.ProcessKeyboardEvent(e.KeyEvent); - } - } - catch (Exception e) - { - Debug.Print("DANGER: Possible callback exception: {0}", e.ToString()); - } - */ - } - - API.CheckEventPredicate check = KeyEventPredicate; - - private static bool KeyEventPredicate(IntPtr display, ref XEvent @event, IntPtr arg) - { - bool ret = false; - try - { - ret = (@event.type == XEventName.KeyRelease || @event.type == XEventName.KeyPress); - } - catch (Exception e) - { - Debug.Print("DANGER: Exception caught during unmanaged callback: {0}", e.ToString()); - } - return ret; } #endregion diff --git a/Source/OpenTK/Platform/X11/X11Keyboard.cs b/Source/OpenTK/Platform/X11/X11Keyboard.cs index c74c4c48..ec8214b1 100644 --- a/Source/OpenTK/Platform/X11/X11Keyboard.cs +++ b/Source/OpenTK/Platform/X11/X11Keyboard.cs @@ -41,6 +41,11 @@ namespace OpenTK.Platform.X11 { if (!keymapExists) { + keymap.Add(XKey.Escape, Key.Escape); + keymap.Add(XKey.Return, Key.Enter); + keymap.Add(XKey.space, Key.Space); + keymap.Add(XKey.BackSpace, Key.BackSpace); + keymap.Add(XKey.Shift_L, Key.ShiftLeft); keymap.Add(XKey.Shift_R, Key.ShiftRight); keymap.Add(XKey.Alt_L, Key.AltLeft); @@ -57,22 +62,21 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.minus, Key.Minus); keymap.Add(XKey.plus, Key.Plus); keymap.Add(XKey.equal, Key.Plus); - //keymap.Add keymap.Add(XKey.Caps_Lock, Key.CapsLock); keymap.Add(XKey.Num_Lock, Key.NumLock); - for (int i = (int)XKey.F1; i < (int)XKey.F35; i++) + for (int i = (int)XKey.F1; i <= (int)XKey.F35; i++) { keymap.Add((XKey)i, (Key)((int)Key.F1 + (i - (int)XKey.F1))); } - for (int i = (int)XKey.a; i < (int)XKey.z; i++) + for (int i = (int)XKey.a; i <= (int)XKey.z; i++) { keymap.Add((XKey)i, (Key)((int)Key.A + (i - (int)XKey.a))); } - for (int i = (int)XKey.A; i < (int)XKey.Z; i++) + for (int i = (int)XKey.A; i <= (int)XKey.Z; i++) { keymap.Add((XKey)i, (Key)((int)Key.A + (i - (int)XKey.A))); } @@ -94,6 +98,8 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.Print, Key.PrintScreen); keymap.Add(XKey.Sys_Req, Key.PrintScreen); + keymap.Add(XKey.backslash, Key.BackSlash); + keymap.Add(XKey.bar, Key.BackSlash); keymap.Add(XKey.braceleft, Key.BracketLeft); keymap.Add(XKey.bracketleft, Key.BracketLeft); keymap.Add(XKey.braceright, Key.BracketRight); @@ -102,6 +108,8 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.semicolon, Key.Semicolon); keymap.Add(XKey.quoteright, Key.Quote); keymap.Add(XKey.quotedbl, Key.Quote); + keymap.Add(XKey.quoteleft, Key.Tilde); + keymap.Add(XKey.asciitilde, Key.Tilde); keymap.Add(XKey.comma, Key.Comma); keymap.Add(XKey.less, Key.Comma); @@ -110,6 +118,35 @@ namespace OpenTK.Platform.X11 keymap.Add(XKey.slash, Key.Slash); keymap.Add(XKey.question, Key.Slash); + keymap.Add(XKey.Left, Key.Left); + keymap.Add(XKey.Down, Key.Down); + keymap.Add(XKey.Right, Key.Right); + keymap.Add(XKey.Up, Key.Up); + + keymap.Add(XKey.Delete, Key.Delete); + keymap.Add(XKey.Home, Key.Home); + keymap.Add(XKey.End, Key.End); + //keymap.Add(XKey.Prior, Key.PageUp); // XKey.Prior == XKey.Page_Up + keymap.Add(XKey.Page_Up, Key.PageUp); + keymap.Add(XKey.Page_Down, Key.PageDown); + //keymap.Add(XKey.Next, Key.PageDown); // XKey.Next == XKey.Page_Down + + keymap.Add(XKey.KP_Add, Key.KeypadAdd); + keymap.Add(XKey.KP_Subtract, Key.KeypadSubtract); + keymap.Add(XKey.KP_Multiply, Key.KeypadMultiply); + keymap.Add(XKey.KP_Divide, Key.KeypadDivide); + keymap.Add(XKey.KP_Decimal, Key.KeypadDecimal); + keymap.Add(XKey.KP_Insert, Key.Keypad0); + keymap.Add(XKey.KP_End, Key.Keypad1); + keymap.Add(XKey.KP_Down, Key.Keypad2); + keymap.Add(XKey.KP_Page_Down, Key.Keypad3); + keymap.Add(XKey.KP_Left, Key.Keypad4); + keymap.Add(XKey.KP_Right, Key.Keypad6); + keymap.Add(XKey.KP_Home, Key.Keypad7); + keymap.Add(XKey.KP_Up, Key.Keypad8); + keymap.Add(XKey.KP_Page_Up, Key.Keypad9); + keymap.Add(XKey.KP_Delete, Key.KeypadDecimal); + keymap.Add(XKey.KP_Enter, Key.Enter); keymapExists = true; } @@ -139,6 +176,7 @@ namespace OpenTK.Platform.X11 kb.Description = "Default X11 keyboard"; kb.NumberOfKeys = lastKeyCode - firstKeyCode + 1; keyboards.Add(kb); + Debug.Print("Keyboard added: {0}", kb.ToString()); } #region internal bool ProcessKeyboardEvent(X11.KeyEvent e) @@ -171,55 +209,11 @@ namespace OpenTK.Platform.X11 else { Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.keycode, (XKey)keysym, (XKey)keysym2); + return false; } return true; } - - return false; - /*API.e.keycode - switch (rin.Header.Type) - { - case API.RawInputDeviceType.KEYBOARD: - bool pressed = - rin.Data.Keyboard.Message == API.Constants.WM_KEYDOWN || - rin.Data.Keyboard.Message == API.Constants.WM_SYSKEYDOWN; - - // Generic control, shift, alt keys may be sent instead of left/right. - // It seems you have to explicitly register left/right events. - switch (rin.Data.Keyboard.VKey) - { - case API.VirtualKeys.SHIFT: - keyboards[0][Input.Key.ShiftLeft] = keyboards[0][Input.Key.ShiftRight] = pressed; - return false; - - case API.VirtualKeys.CONTROL: - keyboards[0][Input.Key.ControlLeft] = keyboards[0][Input.Key.ControlRight] = pressed; - return false; - - case API.VirtualKeys.MENU: - keyboards[0][Input.Key.AltLeft] = keyboards[0][Input.Key.AltRight] = pressed; - return false; - - default: - if (!WinRawKeyboard.KeyMap.ContainsKey(rin.Data.Keyboard.VKey)) - { - Debug.Print("Virtual key {0} not mapped.", rin.Data.Keyboard.VKey); - OpenTK.OpenGL.GL.ClearColor(1.0f, 0.3f, 0.3f, 0.0f); - } - else - { - keyboards[0][WinRawKeyboard.KeyMap[rin.Data.Keyboard.VKey]] = pressed; - OpenTK.OpenGL.GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - } - break; - } - break; - - default: - throw new ApplicationException("Windows raw keyboard driver received invalid data."); - } - return false;*/ } #endregion