00001 #region License
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #endregion
00027
00028 using System;
00029 using System.Diagnostics;
00030 using System.Runtime.InteropServices;
00031 using System.Text;
00032 using OpenTK.Graphics;
00033 using OpenTK.Input;
00034 using System.Collections.Generic;
00035 using System.IO;
00036 using System.Drawing;
00037
00038 namespace OpenTK.Platform.Windows
00039 {
00045 internal sealed class WinGLNative : INativeWindow, IInputDriver
00046 {
00047 #region Fields
00048
00049 readonly static object SyncRoot = new object();
00050
00051 const ExtendedWindowStyle ParentStyleEx = ExtendedWindowStyle.WindowEdge | ExtendedWindowStyle.ApplicationWindow;
00052 const ExtendedWindowStyle ChildStyleEx = 0;
00053
00054 readonly IntPtr Instance = Marshal.GetHINSTANCE(typeof(WinGLNative).Module);
00055 readonly IntPtr ClassName;
00056 readonly WindowProcedure WindowProcedureDelegate;
00057 readonly UIntPtr ModalLoopTimerId;
00058 readonly uint ModalLoopTimerPeriod = 1;
00059 UIntPtr timer_handle;
00060 readonly Functions.TimerProc ModalLoopCallback;
00061
00062 bool class_registered;
00063 bool disposed;
00064 bool exists;
00065 WinWindowInfo window, child_window;
00066 WindowBorder windowBorder = WindowBorder.Resizable;
00067 Nullable<WindowBorder> previous_window_border;
00068 Nullable<WindowBorder> deferred_window_border;
00069 WindowState windowState = WindowState.Normal;
00070 bool borderless_maximized_window_state = false;
00071 bool focused;
00072 bool mouse_outside_window = true;
00073 bool invisible_since_creation;
00074
00075 Rectangle
00076 bounds = new Rectangle(),
00077 client_rectangle = new Rectangle(),
00078 previous_bounds = new Rectangle();
00079 Icon icon;
00080
00081 const ClassStyle DefaultClassStyle = ClassStyle.OwnDC;
00082
00083 readonly IntPtr DefaultWindowProcedure =
00084 Marshal.GetFunctionPointerForDelegate(new WindowProcedure(Functions.DefWindowProc));
00085
00086
00087 WinMMJoystick joystick_driver = new WinMMJoystick();
00088 KeyboardDevice keyboard = new KeyboardDevice();
00089 MouseDevice mouse = new MouseDevice();
00090 IList<KeyboardDevice> keyboards = new List<KeyboardDevice>(1);
00091 IList<MouseDevice> mice = new List<MouseDevice>(1);
00092 internal static readonly WinKeyMap KeyMap = new WinKeyMap();
00093 const long ExtendedBit = 1 << 24;
00094 static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0);
00095
00096 KeyPressEventArgs key_press = new KeyPressEventArgs((char)0);
00097
00098 static int window_count;
00099
00100 #endregion
00101
00102 #region Contructors
00103
00104 public WinGLNative(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device)
00105 {
00106 lock (SyncRoot)
00107 {
00108 ++window_count;
00109 ClassName = Marshal.StringToHGlobalAuto(typeof(WinGLNative).Name + window_count.ToString());
00110 ModalLoopTimerId = new UIntPtr((uint)window_count);
00111 }
00112
00113
00114
00115 WindowProcedureDelegate = WindowProcedure;
00116
00117
00118 ModalLoopCallback = delegate(IntPtr handle, WindowMessage msg, UIntPtr eventId, int time)
00119 {
00120
00121 if (Move != null)
00122 Move(this, EventArgs.Empty);
00123 };
00124
00125
00126
00127 window = new WinWindowInfo(
00128 CreateWindow(x, y, width, height, title, options, device, IntPtr.Zero), null);
00129 child_window = new WinWindowInfo(
00130 CreateWindow(0, 0, ClientSize.Width, ClientSize.Height, title, options, device, window.WindowHandle), window);
00131
00132 exists = true;
00133
00134 keyboard.Description = "Standard Windows keyboard";
00135 keyboard.NumberOfFunctionKeys = 12;
00136 keyboard.NumberOfKeys = 101;
00137 keyboard.NumberOfLeds = 3;
00138
00139 mouse.Description = "Standard Windows mouse";
00140 mouse.NumberOfButtons = 3;
00141 mouse.NumberOfWheels = 1;
00142
00143 keyboards.Add(keyboard);
00144 mice.Add(mouse);
00145 }
00146
00147 #endregion
00148
00149 #region Private Members
00150
00151 #region WindowProcedure
00152
00153 IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
00154 {
00155 switch (message)
00156 {
00157 #region Size / Move / Style events
00158
00159 case WindowMessage.ACTIVATE:
00160
00161
00162 bool new_focused_state = Focused;
00163 if (IntPtr.Size == 4)
00164 focused = (wParam.ToInt32() & 0xFFFF) != 0;
00165 else
00166 focused = (wParam.ToInt64() & 0xFFFF) != 0;
00167
00168 if (new_focused_state != Focused && FocusedChanged != null)
00169 FocusedChanged(this, EventArgs.Empty);
00170 break;
00171
00172 case WindowMessage.ENTERMENULOOP:
00173 case WindowMessage.ENTERSIZEMOVE:
00174
00175
00176
00177 StartTimer(handle);
00178 break;
00179
00180 case WindowMessage.EXITMENULOOP:
00181 case WindowMessage.EXITSIZEMOVE:
00182
00183
00184 StopTimer(handle);
00185 break;
00186
00187 case WindowMessage.ERASEBKGND:
00188 return new IntPtr(1);
00189
00190 case WindowMessage.WINDOWPOSCHANGED:
00191 unsafe
00192 {
00193 WindowPosition* pos = (WindowPosition*)lParam;
00194 if (window != null && pos->hwnd == window.WindowHandle)
00195 {
00196 Point new_location = new Point(pos->x, pos->y);
00197 if (Location != new_location)
00198 {
00199 bounds.Location = new_location;
00200 if (Move != null)
00201 Move(this, EventArgs.Empty);
00202 }
00203
00204 Size new_size = new Size(pos->cx, pos->cy);
00205 if (Size != new_size)
00206 {
00207 bounds.Width = pos->cx;
00208 bounds.Height = pos->cy;
00209
00210 Win32Rectangle rect;
00211 Functions.GetClientRect(handle, out rect);
00212 client_rectangle = rect.ToRectangle();
00213
00214 Functions.SetWindowPos(child_window.WindowHandle, IntPtr.Zero, 0, 0, ClientRectangle.Width, ClientRectangle.Height,
00215 SetWindowPosFlags.NOZORDER | SetWindowPosFlags.NOOWNERZORDER |
00216 SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING);
00217
00218 if (Resize != null)
00219 Resize(this, EventArgs.Empty);
00220 }
00221 }
00222 }
00223 break;
00224
00225 case WindowMessage.STYLECHANGED:
00226 unsafe
00227 {
00228 if (wParam.ToInt64() == (long)GWL.STYLE)
00229 {
00230 WindowStyle style = ((StyleStruct*)lParam)->New;
00231 if ((style & WindowStyle.Popup) != 0)
00232 windowBorder = WindowBorder.Hidden;
00233 else if ((style & WindowStyle.ThickFrame) != 0)
00234 windowBorder = WindowBorder.Resizable;
00235 else if ((style & ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox)) != 0)
00236 windowBorder = WindowBorder.Fixed;
00237 }
00238 }
00239
00240 break;
00241
00242 case WindowMessage.SIZE:
00243 SizeMessage state = (SizeMessage)wParam.ToInt64();
00244 WindowState new_state = windowState;
00245 switch (state)
00246 {
00247 case SizeMessage.RESTORED: new_state = borderless_maximized_window_state ?
00248 WindowState.Maximized : WindowState.Normal; break;
00249 case SizeMessage.MINIMIZED: new_state = WindowState.Minimized; break;
00250 case SizeMessage.MAXIMIZED: new_state = WindowBorder == WindowBorder.Hidden ?
00251 WindowState.Fullscreen : WindowState.Maximized;
00252 break;
00253 }
00254
00255 if (new_state != windowState)
00256 {
00257 windowState = new_state;
00258 if (WindowStateChanged != null)
00259 WindowStateChanged(this, EventArgs.Empty);
00260 }
00261
00262 break;
00263
00264 #endregion
00265
00266 #region Input events
00267
00268 case WindowMessage.CHAR:
00269 if (IntPtr.Size == 4)
00270 key_press.KeyChar = (char)wParam.ToInt32();
00271 else
00272 key_press.KeyChar = (char)wParam.ToInt64();
00273
00274 if (KeyPress != null)
00275 KeyPress(this, key_press);
00276 break;
00277
00278 case WindowMessage.MOUSEMOVE:
00279 Point point = new Point(
00280 (short)((uint)lParam.ToInt32() & 0x0000FFFF),
00281 (short)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16));
00282 mouse.Position = point;
00283
00284 if (mouse_outside_window)
00285 {
00286
00287
00288 mouse_outside_window = false;
00289 EnableMouseTracking();
00290
00291 if (MouseEnter != null)
00292 MouseEnter(this, EventArgs.Empty);
00293 }
00294 break;
00295
00296 case WindowMessage.MOUSELEAVE:
00297 mouse_outside_window = true;
00298
00299
00300 if (MouseLeave != null)
00301 MouseLeave(this, EventArgs.Empty);
00302 break;
00303
00304 case WindowMessage.MOUSEWHEEL:
00305
00306
00307 mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f;
00308 break;
00309
00310 case WindowMessage.LBUTTONDOWN:
00311 mouse[MouseButton.Left] = true;
00312 break;
00313
00314 case WindowMessage.MBUTTONDOWN:
00315 mouse[MouseButton.Middle] = true;
00316 break;
00317
00318 case WindowMessage.RBUTTONDOWN:
00319 mouse[MouseButton.Right] = true;
00320 break;
00321
00322 case WindowMessage.XBUTTONDOWN:
00323 mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = true;
00324 break;
00325
00326 case WindowMessage.LBUTTONUP:
00327 mouse[MouseButton.Left] = false;
00328 break;
00329
00330 case WindowMessage.MBUTTONUP:
00331 mouse[MouseButton.Middle] = false;
00332 break;
00333
00334 case WindowMessage.RBUTTONUP:
00335 mouse[MouseButton.Right] = false;
00336 break;
00337
00338 case WindowMessage.XBUTTONUP:
00339
00340 mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = false;
00341 break;
00342
00343
00344 case WindowMessage.KEYDOWN:
00345 case WindowMessage.KEYUP:
00346 case WindowMessage.SYSKEYDOWN:
00347 case WindowMessage.SYSKEYUP:
00348 bool pressed =
00349 message == WindowMessage.KEYDOWN ||
00350 message == WindowMessage.SYSKEYDOWN;
00351
00352
00353
00354
00355
00356
00357
00358
00359 bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
00360 switch ((VirtualKeys)wParam)
00361 {
00362 case VirtualKeys.SHIFT:
00363
00364
00365
00366
00367
00368
00369
00370 if (ShiftRightScanCode != 0)
00371 {
00372 unchecked
00373 {
00374 if (((lParam.ToInt64() >> 16) & 0xFF) == ShiftRightScanCode)
00375 keyboard[Input.Key.ShiftRight] = pressed;
00376 else
00377 keyboard[Input.Key.ShiftLeft] = pressed;
00378 }
00379 }
00380 else
00381 {
00382
00383 keyboard[Input.Key.ShiftLeft] = pressed;
00384 }
00385 return IntPtr.Zero;
00386
00387 case VirtualKeys.CONTROL:
00388 if (extended)
00389 keyboard[Input.Key.ControlRight] = pressed;
00390 else
00391 keyboard[Input.Key.ControlLeft] = pressed;
00392 return IntPtr.Zero;
00393
00394 case VirtualKeys.MENU:
00395 if (extended)
00396 keyboard[Input.Key.AltRight] = pressed;
00397 else
00398 keyboard[Input.Key.AltLeft] = pressed;
00399 return IntPtr.Zero;
00400
00401 case VirtualKeys.RETURN:
00402 if (extended)
00403 keyboard[Key.KeypadEnter] = pressed;
00404 else
00405 keyboard[Key.Enter] = pressed;
00406 return IntPtr.Zero;
00407
00408 default:
00409 if (!WMInput.KeyMap.ContainsKey((VirtualKeys)wParam))
00410 {
00411 Debug.Print("Virtual key {0} ({1}) not mapped.", (VirtualKeys)wParam, (int)lParam);
00412 break;
00413 }
00414 else
00415 {
00416 keyboard[WMInput.KeyMap[(VirtualKeys)wParam]] = pressed;
00417 }
00418 return IntPtr.Zero;
00419 }
00420 break;
00421
00422 case WindowMessage.SYSCHAR:
00423 return IntPtr.Zero;
00424
00425 case WindowMessage.KILLFOCUS:
00426 keyboard.ClearKeys();
00427 break;
00428
00429 #endregion
00430
00431 #region Creation / Destruction events
00432
00433 case WindowMessage.CREATE:
00434 CreateStruct cs = (CreateStruct)Marshal.PtrToStructure(lParam, typeof(CreateStruct));
00435 if (cs.hwndParent == IntPtr.Zero)
00436 {
00437 bounds.X = cs.x;
00438 bounds.Y = cs.y;
00439 bounds.Width = cs.cx;
00440 bounds.Height = cs.cy;
00441
00442 Win32Rectangle rect;
00443 Functions.GetClientRect(handle, out rect);
00444 client_rectangle = rect.ToRectangle();
00445
00446 invisible_since_creation = true;
00447 }
00448 break;
00449
00450 case WindowMessage.CLOSE:
00451 System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs();
00452
00453 if (Closing != null)
00454 Closing(this, e);
00455
00456 if (!e.Cancel)
00457 {
00458 if (Unload != null)
00459 Unload(this, EventArgs.Empty);
00460
00461 DestroyWindow();
00462 break;
00463 }
00464
00465 return IntPtr.Zero;
00466
00467 case WindowMessage.DESTROY:
00468 exists = false;
00469
00470 Functions.UnregisterClass(ClassName, Instance);
00471 window.Dispose();
00472 child_window.Dispose();
00473
00474 if (Closed != null)
00475 Closed(this, EventArgs.Empty);
00476
00477 break;
00478
00479 #endregion
00480 }
00481
00482 return Functions.DefWindowProc(handle, message, wParam, lParam);
00483 }
00484
00485 private void EnableMouseTracking()
00486 {
00487 TrackMouseEventStructure me = new TrackMouseEventStructure();
00488 me.Size = TrackMouseEventStructure.SizeInBytes;
00489 me.TrackWindowHandle = child_window.WindowHandle;
00490 me.Flags = TrackMouseEventFlags.LEAVE;
00491
00492 if (!Functions.TrackMouseEvent(ref me))
00493 Debug.Print("[Warning] Failed to enable mouse tracking, error: {0}.",
00494 Marshal.GetLastWin32Error());
00495 }
00496
00497 private void StartTimer(IntPtr handle)
00498 {
00499 if (timer_handle == UIntPtr.Zero)
00500 {
00501 timer_handle = Functions.SetTimer(handle, ModalLoopTimerId, ModalLoopTimerPeriod, ModalLoopCallback);
00502 if (timer_handle == UIntPtr.Zero)
00503 Debug.Print("[Warning] Failed to set modal loop timer callback ({0}:{1}->{2}).",
00504 GetType().Name, handle, Marshal.GetLastWin32Error());
00505 }
00506 }
00507
00508 private void StopTimer(IntPtr handle)
00509 {
00510 if (timer_handle != UIntPtr.Zero)
00511 {
00512 if (!Functions.KillTimer(handle, timer_handle))
00513 Debug.Print("[Warning] Failed to kill modal loop timer callback ({0}:{1}->{2}).",
00514 GetType().Name, handle, Marshal.GetLastWin32Error());
00515 timer_handle = UIntPtr.Zero;
00516 }
00517 }
00518
00519 #endregion
00520
00521 #region IsIdle
00522
00523 bool IsIdle
00524 {
00525 get
00526 {
00527 MSG message = new MSG();
00528 return !Functions.PeekMessage(ref message, window.WindowHandle, 0, 0, 0);
00529 }
00530 }
00531
00532 #endregion
00533
00534 #region CreateWindow
00535
00536 IntPtr CreateWindow(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device, IntPtr parentHandle)
00537 {
00538
00539
00540
00541
00542
00543 WindowStyle style = 0;
00544 ExtendedWindowStyle ex_style = 0;
00545 if (parentHandle == IntPtr.Zero)
00546 {
00547 style |= WindowStyle.OverlappedWindow | WindowStyle.ClipChildren;
00548 ex_style = ParentStyleEx;
00549 }
00550 else
00551 {
00552 style |= WindowStyle.Visible | WindowStyle.Child | WindowStyle.ClipSiblings;
00553 ex_style = ChildStyleEx;
00554 }
00555
00556
00557 Win32Rectangle rect = new Win32Rectangle();
00558 rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height;
00559 Functions.AdjustWindowRectEx(ref rect, style, false, ex_style);
00560
00561
00562
00563 if (!class_registered)
00564 {
00565 ExtendedWindowClass wc = new ExtendedWindowClass();
00566 wc.Size = ExtendedWindowClass.SizeInBytes;
00567 wc.Style = DefaultClassStyle;
00568 wc.Instance = Instance;
00569 wc.WndProc = WindowProcedureDelegate;
00570 wc.ClassName = ClassName;
00571 wc.Icon = Icon != null ? Icon.Handle : IntPtr.Zero;
00572 #warning "This seems to resize one of the 'large' icons, rather than using a small icon directly (multi-icon files). Investigate!"
00573 wc.IconSm = Icon != null ? new Icon(Icon, 16, 16).Handle : IntPtr.Zero;
00574 wc.Cursor = Functions.LoadCursor(CursorName.Arrow);
00575 ushort atom = Functions.RegisterClassEx(ref wc);
00576
00577 if (atom == 0)
00578 throw new PlatformException(String.Format("Failed to register window class. Error: {0}", Marshal.GetLastWin32Error()));
00579
00580 class_registered = true;
00581 }
00582
00583 IntPtr window_name = Marshal.StringToHGlobalAuto(title);
00584 IntPtr handle = Functions.CreateWindowEx(
00585 ex_style, ClassName, window_name, style,
00586 rect.left, rect.top, rect.Width, rect.Height,
00587 parentHandle, IntPtr.Zero, Instance, IntPtr.Zero);
00588
00589 if (handle == IntPtr.Zero)
00590 throw new PlatformException(String.Format("Failed to create window. Error: {0}", Marshal.GetLastWin32Error()));
00591
00592 return handle;
00593 }
00594
00595 #endregion
00596
00597 #region DestroyWindow
00598
00602 void DestroyWindow()
00603 {
00604 if (Exists)
00605 {
00606 Debug.Print("Destroying window: {0}", window.ToString());
00607 Functions.DestroyWindow(window.WindowHandle);
00608 exists = false;
00609 }
00610 }
00611
00612 #endregion
00613
00614 #endregion
00615
00616 #region INativeWindow Members
00617
00618 #region Bounds
00619
00620 public Rectangle Bounds
00621 {
00622 get { return bounds; }
00623 set
00624 {
00625
00626 Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, value.X, value.Y, value.Width, value.Height, 0);
00627 }
00628 }
00629
00630 #endregion
00631
00632 #region Location
00633
00634 public Point Location
00635 {
00636 get { return Bounds.Location; }
00637 set
00638 {
00639
00640 Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, value.X, value.Y, 0, 0, SetWindowPosFlags.NOSIZE);
00641 }
00642 }
00643
00644 #endregion
00645
00646 #region Size
00647
00648 public Size Size
00649 {
00650 get { return Bounds.Size; }
00651 set
00652 {
00653
00654 Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, 0, 0, value.Width, value.Height, SetWindowPosFlags.NOMOVE);
00655 }
00656 }
00657
00658 #endregion
00659
00660 #region ClientRectangle
00661
00662 public Rectangle ClientRectangle
00663 {
00664 get
00665 {
00666 if (client_rectangle.Width == 0)
00667 client_rectangle.Width = 1;
00668 if (client_rectangle.Height == 0)
00669 client_rectangle.Height = 1;
00670 return client_rectangle;
00671 }
00672 set
00673 {
00674 ClientSize = value.Size;
00675 }
00676 }
00677
00678 #endregion
00679
00680 #region ClientSize
00681
00682 public Size ClientSize
00683 {
00684 get
00685 {
00686 return ClientRectangle.Size;
00687 }
00688 set
00689 {
00690 WindowStyle style = (WindowStyle)Functions.GetWindowLong(window.WindowHandle, GetWindowLongOffsets.STYLE);
00691 Win32Rectangle rect = Win32Rectangle.From(value);
00692 Functions.AdjustWindowRect(ref rect, style, false);
00693 Size = new Size(rect.Width, rect.Height);
00694 }
00695 }
00696
00697 #endregion
00698
00699 #region Width
00700
00701 public int Width
00702 {
00703 get { return ClientRectangle.Width; }
00704 set { ClientRectangle = new Rectangle(Location, new Size(value, Height)); }
00705 }
00706
00707 #endregion
00708
00709 #region Height
00710
00711 public int Height
00712 {
00713 get { return ClientRectangle.Height; }
00714 set { ClientRectangle = new Rectangle(Location, new Size(Width, value)); }
00715 }
00716
00717 #endregion
00718
00719 #region X
00720
00721 public int X
00722 {
00723 get { return Location.X; }
00724 set { Location = new Point(value, Y); }
00725 }
00726
00727 #endregion
00728
00729 #region Y
00730
00731 public int Y
00732 {
00733 get { return Location.Y; }
00734 set { Location = new Point(X, value); }
00735 }
00736
00737 #endregion
00738
00739 #region Icon
00740
00741 public Icon Icon
00742 {
00743 get
00744 {
00745 return icon;
00746 }
00747 set
00748 {
00749 icon = value;
00750 if (window.WindowHandle != IntPtr.Zero)
00751 {
00752 Functions.SendMessage(window.WindowHandle, WindowMessage.SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle);
00753 Functions.SendMessage(window.WindowHandle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle);
00754 }
00755 }
00756 }
00757
00758 #endregion
00759
00760 #region Focused
00761
00762 public bool Focused
00763 {
00764 get { return focused; }
00765 }
00766
00767 #endregion
00768
00769 #region Title
00770
00771 StringBuilder sb_title = new StringBuilder(256);
00772 public string Title
00773 {
00774 get
00775 {
00776 sb_title.Remove(0, sb_title.Length);
00777 if (Functions.GetWindowText(window.WindowHandle, sb_title, sb_title.MaxCapacity) == 0)
00778 Debug.Print("Failed to retrieve window title (window:{0}, reason:{2}).", window.WindowHandle, Marshal.GetLastWin32Error());
00779 return sb_title.ToString();
00780 }
00781 set
00782 {
00783 if (!Functions.SetWindowText(window.WindowHandle, value))
00784 Debug.Print("Failed to change window title (window:{0}, new title:{1}, reason:{2}).", window.WindowHandle, value, Marshal.GetLastWin32Error());
00785 }
00786 }
00787
00788 #endregion
00789
00790 #region Visible
00791
00792 public bool Visible
00793 {
00794 get
00795 {
00796 return Functions.IsWindowVisible(window.WindowHandle);
00797 }
00798 set
00799 {
00800 if (value)
00801 {
00802 Functions.ShowWindow(window.WindowHandle, ShowWindowCommand.SHOW);
00803 if (invisible_since_creation)
00804 {
00805 Functions.BringWindowToTop(window.WindowHandle);
00806 Functions.SetForegroundWindow(window.WindowHandle);
00807 }
00808 }
00809 else if (!value)
00810 {
00811 Functions.ShowWindow(window.WindowHandle, ShowWindowCommand.HIDE);
00812 }
00813 }
00814 }
00815
00816 #endregion
00817
00818 #region Exists
00819
00820 public bool Exists { get { return exists; } }
00821
00822 #endregion
00823
00824 #region Close
00825
00826 public void Close()
00827 {
00828 Functions.PostMessage(window.WindowHandle, WindowMessage.CLOSE, IntPtr.Zero, IntPtr.Zero);
00829 }
00830
00831 #endregion
00832
00833 #region public WindowState WindowState
00834
00835 public WindowState WindowState
00836 {
00837 get
00838 {
00839 return windowState;
00840 }
00841 set
00842 {
00843 if (WindowState == value)
00844 return;
00845
00846 ShowWindowCommand command = 0;
00847 bool exiting_fullscreen = false;
00848 borderless_maximized_window_state = false;
00849
00850 switch (value)
00851 {
00852 case WindowState.Normal:
00853 command = ShowWindowCommand.RESTORE;
00854
00855
00856 if (WindowState == WindowState.Fullscreen)
00857 exiting_fullscreen = true;
00858 break;
00859
00860 case WindowState.Maximized:
00861
00862
00863
00864
00865
00866 WindowState = WindowState.Normal;
00867
00868 if (WindowBorder == WindowBorder.Hidden)
00869 {
00870 IntPtr current_monitor = Functions.MonitorFromWindow(window.WindowHandle, MonitorFrom.Nearest);
00871 MonitorInfo info = new MonitorInfo();
00872 info.Size = MonitorInfo.SizeInBytes;
00873 Functions.GetMonitorInfo(current_monitor, ref info);
00874
00875 previous_bounds = Bounds;
00876 borderless_maximized_window_state = true;
00877 Bounds = info.Work.ToRectangle();
00878 }
00879 else
00880 {
00881 command = ShowWindowCommand.MAXIMIZE;
00882 }
00883 break;
00884
00885 case WindowState.Minimized:
00886 command = ShowWindowCommand.MINIMIZE;
00887 break;
00888
00889 case WindowState.Fullscreen:
00890
00891
00892
00893
00894
00895 WindowState = WindowState.Normal;
00896
00897 previous_bounds = Bounds;
00898 previous_window_border = WindowBorder;
00899 WindowBorder = WindowBorder.Hidden;
00900 command = ShowWindowCommand.MAXIMIZE;
00901
00902 Functions.SetForegroundWindow(window.WindowHandle);
00903
00904 break;
00905 }
00906
00907 if (command != 0)
00908 Functions.ShowWindow(window.WindowHandle, command);
00909
00910
00911 if (exiting_fullscreen)
00912 {
00913 WindowBorder =
00914 deferred_window_border.HasValue ? deferred_window_border.Value :
00915 previous_window_border.HasValue ? previous_window_border.Value :
00916 WindowBorder;
00917 deferred_window_border = previous_window_border = null;
00918 }
00919
00920
00921 if (command == ShowWindowCommand.RESTORE && previous_bounds != Rectangle.Empty)
00922 {
00923 Bounds = previous_bounds;
00924 previous_bounds = Rectangle.Empty;
00925 }
00926 }
00927 }
00928
00929 #endregion
00930
00931 #region public WindowBorder WindowBorder
00932
00933 public WindowBorder WindowBorder
00934 {
00935 get
00936 {
00937 return windowBorder;
00938 }
00939 set
00940 {
00941
00942
00943 if (WindowState == WindowState.Fullscreen)
00944 {
00945 deferred_window_border = value;
00946 return;
00947 }
00948
00949 if (windowBorder == value)
00950 return;
00951
00952
00953
00954
00955 bool was_visible = Visible;
00956
00957
00958
00959 WindowState state = WindowState;
00960 WindowState = WindowState.Normal;
00961
00962 WindowStyle style = WindowStyle.ClipChildren | WindowStyle.ClipSiblings;
00963
00964 switch (value)
00965 {
00966 case WindowBorder.Resizable:
00967 style |= WindowStyle.OverlappedWindow;
00968 break;
00969
00970 case WindowBorder.Fixed:
00971 style |= WindowStyle.OverlappedWindow &
00972 ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox | WindowStyle.SizeBox);
00973 break;
00974
00975 case WindowBorder.Hidden:
00976 style |= WindowStyle.Popup;
00977 break;
00978 }
00979
00980
00981 Size client_size = ClientSize;
00982 Win32Rectangle rect = Win32Rectangle.From(client_size);
00983 Functions.AdjustWindowRectEx(ref rect, style, false, ParentStyleEx);
00984
00985
00986 if (was_visible)
00987 Visible = false;
00988
00989 Functions.SetWindowLong(window.WindowHandle, GetWindowLongOffsets.STYLE, (IntPtr)(int)style);
00990 Functions.SetWindowPos(window.WindowHandle, IntPtr.Zero, 0, 0, rect.Width, rect.Height,
00991 SetWindowPosFlags.NOMOVE | SetWindowPosFlags.NOZORDER |
00992 SetWindowPosFlags.FRAMECHANGED);
00993
00994
00995
00996
00997 if (was_visible)
00998 Visible = true;
00999
01000 WindowState = state;
01001
01002 if (WindowBorderChanged != null)
01003 WindowBorderChanged(this, EventArgs.Empty);
01004 }
01005 }
01006
01007 #endregion
01008
01009 #region PointToClient
01010
01011 public Point PointToClient(Point point)
01012 {
01013 if (!Functions.ScreenToClient(window.WindowHandle, ref point))
01014 throw new InvalidOperationException(String.Format(
01015 "Could not convert point {0} from client to screen coordinates. Windows error: {1}",
01016 point.ToString(), Marshal.GetLastWin32Error()));
01017
01018 return point;
01019 }
01020
01021 #endregion
01022
01023 #region PointToScreen
01024
01025 public Point PointToScreen(Point p)
01026 {
01027 throw new NotImplementedException();
01028 }
01029
01030 #endregion
01031
01032 #region Events
01033
01034 public event EventHandler<EventArgs> Idle;
01035
01036 public event EventHandler<EventArgs> Load;
01037
01038 public event EventHandler<EventArgs> Unload;
01039
01040 public event EventHandler<EventArgs> Move;
01041
01042 public event EventHandler<EventArgs> Resize;
01043
01044 public event EventHandler<System.ComponentModel.CancelEventArgs> Closing;
01045
01046 public event EventHandler<EventArgs> Closed;
01047
01048 public event EventHandler<EventArgs> Disposed;
01049
01050 public event EventHandler<EventArgs> IconChanged;
01051
01052 public event EventHandler<EventArgs> TitleChanged;
01053
01054 public event EventHandler<EventArgs> ClientSizeChanged;
01055
01056 public event EventHandler<EventArgs> VisibleChanged;
01057
01058 public event EventHandler<EventArgs> WindowInfoChanged;
01059
01060 public event EventHandler<EventArgs> FocusedChanged;
01061
01062 public event EventHandler<EventArgs> WindowBorderChanged;
01063
01064 public event EventHandler<EventArgs> WindowStateChanged;
01065
01066 public event EventHandler<KeyPressEventArgs> KeyPress;
01067
01068 public event EventHandler<EventArgs> MouseEnter;
01069
01070 public event EventHandler<EventArgs> MouseLeave;
01071
01072 #endregion
01073
01074 #endregion
01075
01076 #region INativeGLWindow Members
01077
01078 #region public void ProcessEvents()
01079
01080 private int ret;
01081 MSG msg;
01082 public void ProcessEvents()
01083 {
01084 while (!IsIdle)
01085 {
01086 ret = Functions.GetMessage(ref msg, window.WindowHandle, 0, 0);
01087 if (ret == -1)
01088 {
01089 throw new PlatformException(String.Format(
01090 "An error happened while processing the message queue. Windows error: {0}",
01091 Marshal.GetLastWin32Error()));
01092 }
01093
01094 Functions.TranslateMessage(ref msg);
01095 Functions.DispatchMessage(ref msg);
01096 }
01097 }
01098
01099 #endregion
01100
01101 #region public IInputDriver InputDriver
01102
01103 public IInputDriver InputDriver
01104 {
01105 get { return this; }
01106 }
01107
01108 #endregion
01109
01110 #region public IWindowInfo WindowInfo
01111
01112 public IWindowInfo WindowInfo
01113 {
01114 get { return child_window; }
01115 }
01116
01117 #endregion
01118
01119 #endregion
01120
01121 #region IInputDriver Members
01122
01123 public void Poll()
01124 {
01125 joystick_driver.Poll();
01126 }
01127
01128 #endregion
01129
01130 #region IKeyboardDriver Members
01131
01132 public IList<KeyboardDevice> Keyboard
01133 {
01134 get { return keyboards; }
01135 }
01136
01137 #endregion
01138
01139 #region IMouseDriver Members
01140
01141 public IList<MouseDevice> Mouse
01142 {
01143 get { return mice; }
01144 }
01145
01146 #endregion
01147
01148 #region IJoystickDriver Members
01149
01150 public IList<JoystickDevice> Joysticks
01151 {
01152 get { return joystick_driver.Joysticks; }
01153 }
01154
01155 #endregion
01156
01157 #region IDisposable Members
01158
01159 public void Dispose()
01160 {
01161 this.Dispose(true);
01162 GC.SuppressFinalize(this);
01163 }
01164
01165 void Dispose(bool calledManually)
01166 {
01167 if (!disposed)
01168 {
01169 if (calledManually)
01170 {
01171
01172 DestroyWindow();
01173 if (Icon != null)
01174 Icon.Dispose();
01175 }
01176 else
01177 {
01178 Debug.Print("[Warning] INativeWindow leaked ({0}). Did you forget to call INativeWindow.Dispose()?", this);
01179 }
01180
01181 disposed = true;
01182 }
01183 }
01184
01185 ~WinGLNative()
01186 {
01187 Dispose(false);
01188 }
01189
01190 #endregion
01191 }
01192 }