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.Collections.Generic;
00030 using System.ComponentModel;
00031 using System.Diagnostics;
00032 using System.Reflection;
00033 using System.Runtime.InteropServices;
00034 using System.Text;
00035 using OpenTK.Graphics;
00036 using OpenTK.Input;
00037 using System.Drawing;
00038
00039 namespace OpenTK.Platform.X11
00040 {
00046 internal sealed class X11GLNative : INativeWindow, IDisposable
00047 {
00048
00049
00050
00051
00052 #region Fields
00053
00054 const int _min_width = 30, _min_height = 30;
00055
00056 X11WindowInfo window = new X11WindowInfo();
00057 X11Input driver;
00058
00059
00060
00061
00062 const string MOTIF_WM_ATOM = "_MOTIF_WM_HINTS";
00063 const string KDE_WM_ATOM = "KWM_WIN_DECORATION";
00064 const string KDE_NET_WM_ATOM = "_KDE_NET_WM_WINDOW_TYPE";
00065 const string ICCM_WM_ATOM = "_NET_WM_WINDOW_TYPE";
00066 const string ICON_NET_ATOM = "_NET_WM_ICON";
00067
00068
00069 IntPtr _atom_wm_destroy;
00070
00071 IntPtr _atom_net_wm_state;
00072 IntPtr _atom_net_wm_state_minimized;
00073 IntPtr _atom_net_wm_state_fullscreen;
00074 IntPtr _atom_net_wm_state_maximized_horizontal;
00075 IntPtr _atom_net_wm_state_maximized_vertical;
00076
00077 IntPtr _atom_net_wm_allowed_actions;
00078 IntPtr _atom_net_wm_action_resize;
00079 IntPtr _atom_net_wm_action_maximize_horizontally;
00080 IntPtr _atom_net_wm_action_maximize_vertically;
00081
00082 IntPtr _atom_net_wm_icon;
00083
00084 readonly IntPtr _atom_xa_cardinal = new IntPtr(6);
00085
00086
00087
00088
00089
00090 static readonly IntPtr _atom_remove = (IntPtr)0;
00091 static readonly IntPtr _atom_add = (IntPtr)1;
00092 static readonly IntPtr _atom_toggle = (IntPtr)2;
00093
00094 Rectangle bounds, client_rectangle;
00095 int border_width;
00096 Icon icon;
00097 bool has_focus;
00098 bool visible;
00099
00100
00101 XEvent e = new XEvent();
00102
00103 bool disposed;
00104 bool exists;
00105 bool isExiting;
00106
00107 bool _decorations_hidden = false;
00108
00109
00110 readonly byte[] ascii = new byte[16];
00111 readonly char[] chars = new char[16];
00112 readonly KeyPressEventArgs KPEventArgs = new KeyPressEventArgs('\0');
00113
00114 #endregion
00115
00116 #region Constructors
00117
00118 public X11GLNative(int x, int y, int width, int height, string title,
00119 GraphicsMode mode,GameWindowFlags options, DisplayDevice device)
00120 : this()
00121 {
00122 if (width <= 0)
00123 throw new ArgumentOutOfRangeException("width", "Must be higher than zero.");
00124 if (height <= 0)
00125 throw new ArgumentOutOfRangeException("height", "Must be higher than zero.");
00126
00127 XVisualInfo info = new XVisualInfo();
00128
00129 Debug.Indent();
00130
00131 using (new XLock(window.Display))
00132 {
00133 if (!mode.Index.HasValue)
00134 throw new GraphicsModeException("Invalid or unsupported GraphicsMode.");
00135
00136 info.VisualID = mode.Index.Value;
00137 int dummy;
00138 window.VisualInfo = (XVisualInfo)Marshal.PtrToStructure(
00139 Functions.XGetVisualInfo(window.Display, XVisualInfoMask.ID, ref info, out dummy), typeof(XVisualInfo));
00140
00141
00142 Debug.Write("Opening render window... ");
00143
00144 XSetWindowAttributes attributes = new XSetWindowAttributes();
00145 attributes.background_pixel = IntPtr.Zero;
00146 attributes.border_pixel = IntPtr.Zero;
00147 attributes.colormap = Functions.XCreateColormap(window.Display, window.RootWindow, window.VisualInfo.Visual, 0);
00148 window.EventMask = EventMask.StructureNotifyMask | EventMask.ExposureMask |
00149 EventMask.KeyReleaseMask | EventMask.KeyPressMask | EventMask.KeymapStateMask |
00150 EventMask.PointerMotionMask | EventMask.FocusChangeMask |
00151 EventMask.ButtonPressMask | EventMask.ButtonReleaseMask |
00152 EventMask.EnterWindowMask | EventMask.LeaveWindowMask |
00153 EventMask.PropertyChangeMask;
00154 attributes.event_mask = (IntPtr)window.EventMask;
00155
00156 uint mask = (uint)SetWindowValuemask.ColorMap | (uint)SetWindowValuemask.EventMask |
00157 (uint)SetWindowValuemask.BackPixel | (uint)SetWindowValuemask.BorderPixel;
00158
00159 window.WindowHandle = Functions.XCreateWindow(window.Display, window.RootWindow,
00160 x, y, width, height, 0, window.VisualInfo.Depth,
00161 (int)CreateWindowArgs.InputOutput, window.VisualInfo.Visual, (UIntPtr)mask, ref attributes);
00162
00163 if (window.WindowHandle == IntPtr.Zero)
00164 throw new ApplicationException("XCreateWindow call failed (returned 0).");
00165 }
00166
00167
00168 SetWindowMinMax(_min_width, _min_height, -1, -1);
00169
00170 XSizeHints hints = new XSizeHints();
00171 hints.base_width = width;
00172 hints.base_height = height;
00173 hints.flags = (IntPtr)(XSizeHintsFlags.PSize | XSizeHintsFlags.PPosition);
00174 using (new XLock(window.Display))
00175 {
00176 Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints);
00177
00178
00179 Functions.XSetWMProtocols(window.Display, window.WindowHandle, new IntPtr[] { _atom_wm_destroy }, 1);
00180 }
00181
00182 driver = new X11Input(window);
00183
00184 Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle));
00185 Debug.Unindent();
00186
00187 exists = true;
00188 }
00189
00194 public X11GLNative()
00195 {
00196 try
00197 {
00198 Debug.Print("Creating X11GLNative window.");
00199 Debug.Indent();
00200
00201
00202 window.Display = Functions.XOpenDisplay(IntPtr.Zero);
00203
00204 if (window.Display == IntPtr.Zero)
00205 throw new Exception("Could not open connection to X");
00206
00207 using (new XLock(window.Display))
00208 {
00209 window.Screen = Functions.XDefaultScreen(window.Display);
00210 window.RootWindow = Functions.XRootWindow(window.Display, window.Screen);
00211 }
00212
00213 Debug.Print("Display: {0}, Screen {1}, Root window: {2}", window.Display, window.Screen,
00214 window.RootWindow);
00215
00216 RegisterAtoms(window);
00217 }
00218 finally
00219 {
00220 Debug.Unindent();
00221 }
00222 }
00223
00224 #endregion
00225
00226 #region Private Members
00227
00228 #region private void RegisterAtoms()
00229
00234 private void RegisterAtoms(X11WindowInfo window)
00235 {
00236 using (new XLock(window.Display))
00237 {
00238 Debug.WriteLine("Registering atoms.");
00239 _atom_wm_destroy = Functions.XInternAtom(window.Display, "WM_DELETE_WINDOW", true);
00240
00241 _atom_net_wm_state = Functions.XInternAtom(window.Display, "_NET_WM_STATE", false);
00242 _atom_net_wm_state_minimized = Functions.XInternAtom(window.Display, "_NET_WM_STATE_MINIMIZED", false);
00243 _atom_net_wm_state_fullscreen = Functions.XInternAtom(window.Display, "_NET_WM_STATE_FULLSCREEN", false);
00244 _atom_net_wm_state_maximized_horizontal =
00245 Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_HORZ", false);
00246 _atom_net_wm_state_maximized_vertical =
00247 Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_VERT", false);
00248
00249 _atom_net_wm_allowed_actions =
00250 Functions.XInternAtom(window.Display, "_NET_WM_ALLOWED_ACTIONS", false);
00251 _atom_net_wm_action_resize =
00252 Functions.XInternAtom(window.Display, "_NET_WM_ACTION_RESIZE", false);
00253 _atom_net_wm_action_maximize_horizontally =
00254 Functions.XInternAtom(window.Display, "_NET_WM_ACTION_MAXIMIZE_HORZ", false);
00255 _atom_net_wm_action_maximize_vertically =
00256 Functions.XInternAtom(window.Display, "_NET_WM_ACTION_MAXIMIZE_VERT", false);
00257
00258 _atom_net_wm_icon =
00259 Functions.XInternAtom(window.Display, "_NEW_WM_ICON", false);
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 }
00273 }
00274
00275 #endregion
00276
00277 #region SetWindowMinMax
00278
00279 void SetWindowMinMax(short min_width, short min_height, short max_width, short max_height)
00280 {
00281 IntPtr dummy;
00282 XSizeHints hints = new XSizeHints();
00283
00284 using (new XLock(window.Display))
00285 {
00286 Functions.XGetWMNormalHints(window.Display, window.WindowHandle, ref hints, out dummy);
00287 }
00288
00289 if (min_width > 0 || min_height > 0)
00290 {
00291 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
00292 hints.min_width = min_width;
00293 hints.min_height = min_height;
00294 }
00295 else
00296 hints.flags = (IntPtr)((int)hints.flags & ~(int)XSizeHintsFlags.PMinSize);
00297
00298 if (max_width > 0 || max_height > 0)
00299 {
00300 hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
00301 hints.max_width = max_width;
00302 hints.max_height = max_height;
00303 }
00304 else
00305 hints.flags = (IntPtr)((int)hints.flags & ~(int)XSizeHintsFlags.PMaxSize);
00306
00307 if (hints.flags != IntPtr.Zero)
00308 {
00309
00310
00311
00312 using (new XLock(window.Display))
00313 {
00314 Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints);
00315 }
00316 }
00317 }
00318
00319 #endregion
00320
00321 #region IsWindowBorderResizable
00322
00323 bool IsWindowBorderResizable
00324 {
00325 get
00326 {
00327 IntPtr actual_atom;
00328 int actual_format;
00329 IntPtr nitems;
00330 IntPtr bytes_after;
00331 IntPtr prop = IntPtr.Zero;
00332 IntPtr atom;
00333
00334
00335 using (new XLock(window.Display))
00336 {
00337 Functions.XGetWindowProperty(window.Display, window.WindowHandle,
00338 _atom_net_wm_allowed_actions, IntPtr.Zero, new IntPtr(256), false,
00339 IntPtr.Zero, out actual_atom, out actual_format, out nitems,
00340 out bytes_after, ref prop);
00341 if ((long)nitems > 0 && prop != IntPtr.Zero)
00342 {
00343 for (int i = 0; i < (long)nitems; i++)
00344 {
00345 atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size);
00346
00347 if (atom == _atom_net_wm_action_resize)
00348 return true;
00349 }
00350 Functions.XFree(prop);
00351 }
00352 }
00353
00354 return false;
00355 }
00356 }
00357
00358 #endregion
00359
00360 #region bool IsWindowBorderHidden
00361
00362 bool IsWindowBorderHidden
00363 {
00364 get
00365 {
00366
00367
00368
00369
00370 IntPtr prop = IntPtr.Zero;
00371
00372
00373
00374 using (new XLock(window.Display))
00375 {
00376
00377 IntPtr motif_hints_atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true);
00378 if (motif_hints_atom != IntPtr.Zero)
00379 {
00380
00381 if (_decorations_hidden)
00382 return true;
00383 }
00384
00385
00386
00387
00388 IntPtr transient_for_parent;
00389 Functions.XGetTransientForHint(window.Display, window.WindowHandle, out transient_for_parent);
00390 if (transient_for_parent != IntPtr.Zero)
00391 return true;
00392
00393 return false;
00394 }
00395 }
00396 }
00397
00398 #endregion
00399
00400 #region void DisableWindowDecorations()
00401
00402 void DisableWindowDecorations()
00403 {
00404 if (DisableMotifDecorations())
00405 {
00406 Debug.Print("Removed decorations through motif.");
00407 _decorations_hidden = true;
00408 }
00409
00410 using (new XLock(window.Display))
00411 {
00412
00413
00414
00415 Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow);
00416
00417 if (_decorations_hidden)
00418 {
00419 Functions.XUnmapWindow(this.window.Display, this.Handle);
00420 Functions.XMapWindow(this.window.Display, this.Handle);
00421 }
00422 }
00423 }
00424
00425 #region bool DisableMotifDecorations()
00426
00427 bool DisableMotifDecorations()
00428 {
00429 using (new XLock(window.Display))
00430 {
00431 IntPtr atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true);
00432 if (atom != IntPtr.Zero)
00433 {
00434
00435
00436 MotifWmHints hints = new MotifWmHints();
00437 hints.flags = (IntPtr)MotifFlags.Decorations;
00438 Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
00439 ref hints, Marshal.SizeOf(hints) / IntPtr.Size);
00440 return true;
00441 }
00442 return false;
00443 }
00444 }
00445
00446 #endregion
00447
00448 #region bool DisableGnomeDecorations()
00449
00450 bool DisableGnomeDecorations()
00451 {
00452 using (new XLock(window.Display))
00453 {
00454 IntPtr atom = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_HINTS, true);
00455 if (atom != IntPtr.Zero)
00456 {
00457 IntPtr hints = IntPtr.Zero;
00458 Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
00459 ref hints, Marshal.SizeOf(hints) / IntPtr.Size);
00460 return true;
00461 }
00462
00463 return false;
00464 }
00465 }
00466
00467 #endregion
00468
00469 #endregion
00470
00471 #region void EnableWindowDecorations()
00472
00473 void EnableWindowDecorations()
00474 {
00475 if (EnableMotifDecorations())
00476 {
00477 Debug.Print("Activated decorations through motif.");
00478 _decorations_hidden = false;
00479 }
00480
00481
00482
00483 using (new XLock(window.Display))
00484 {
00485 Functions.XSetTransientForHint(this.window.Display, this.Handle, IntPtr.Zero);
00486
00487 if (!_decorations_hidden)
00488 {
00489 Functions.XUnmapWindow(this.window.Display, this.Handle);
00490 Functions.XMapWindow(this.window.Display, this.Handle);
00491 }
00492 }
00493 }
00494
00495 #region bool EnableMotifDecorations()
00496
00497 bool EnableMotifDecorations()
00498 {
00499 using (new XLock(window.Display))
00500 {
00501 IntPtr atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true);
00502 if (atom != IntPtr.Zero)
00503 {
00504
00505 MotifWmHints hints = new MotifWmHints();
00506 hints.flags = (IntPtr)MotifFlags.Decorations;
00507 hints.decorations = (IntPtr)MotifDecorations.All;
00508 Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
00509 ref hints, Marshal.SizeOf(hints) / IntPtr.Size);
00510
00511 return true;
00512 }
00513 return false;
00514 }
00515 }
00516
00517 #endregion
00518
00519 #region bool EnableGnomeDecorations()
00520
00521 bool EnableGnomeDecorations()
00522 {
00523 using (new XLock(window.Display))
00524 {
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 IntPtr atom = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_HINTS, true);
00535 if (atom != IntPtr.Zero)
00536 {
00537 Functions.XDeleteProperty(this.window.Display, this.Handle, atom);
00538 return true;
00539 }
00540
00541 return false;
00542 }
00543 }
00544
00545 #endregion
00546
00547 #endregion
00548
00549 #region DeleteIconPixmaps
00550
00551 static void DeleteIconPixmaps(IntPtr display, IntPtr window)
00552 {
00553 using (new XLock(display))
00554 {
00555 IntPtr wmHints_ptr = Functions.XGetWMHints(display, window);
00556
00557 if (wmHints_ptr != IntPtr.Zero)
00558 {
00559 XWMHints wmHints = (XWMHints)Marshal.PtrToStructure(wmHints_ptr, typeof(XWMHints));
00560 XWMHintsFlags flags = (XWMHintsFlags)wmHints.flags.ToInt32();
00561
00562 if ((flags & XWMHintsFlags.IconPixmapHint) != 0)
00563 {
00564 wmHints.flags = new IntPtr((int)(flags & ~XWMHintsFlags.IconPixmapHint));
00565 Functions.XFreePixmap(display, wmHints.icon_pixmap);
00566 }
00567
00568 if ((flags & XWMHintsFlags.IconMaskHint) != 0)
00569 {
00570 wmHints.flags = new IntPtr((int)(flags & ~XWMHintsFlags.IconMaskHint));
00571 Functions.XFreePixmap(display, wmHints.icon_mask);
00572 }
00573
00574 Functions.XSetWMHints(display, window, ref wmHints);
00575 Functions.XFree(wmHints_ptr);
00576 }
00577 }
00578 }
00579
00580 #endregion
00581
00582 #endregion
00583
00584 #region INativeWindow Members
00585
00586 #region ProcessEvents
00587
00588 public void ProcessEvents()
00589 {
00590
00591 while (Exists && window != null)
00592 {
00593 using (new XLock(window.Display))
00594 {
00595 if (!Functions.XCheckWindowEvent(window.Display, window.WindowHandle, window.EventMask, ref e) &&
00596 !Functions.XCheckTypedWindowEvent(window.Display, window.WindowHandle, XEventName.ClientMessage, ref e))
00597 break;
00598 }
00599
00600
00601 switch (e.type)
00602 {
00603 case XEventName.MapNotify:
00604 {
00605 bool previous_visible = visible;
00606 visible = true;
00607 if (visible != previous_visible)
00608 if (VisibleChanged != null)
00609 VisibleChanged(this, EventArgs.Empty);
00610 }
00611 return;
00612
00613 case XEventName.UnmapNotify:
00614 {
00615 bool previous_visible = visible;
00616 visible = false;
00617 if (visible != previous_visible)
00618 if (VisibleChanged != null)
00619 VisibleChanged(this, EventArgs.Empty);
00620 }
00621 break;
00622
00623 case XEventName.CreateNotify:
00624
00625 break;
00626
00627 case XEventName.ClientMessage:
00628 if (!isExiting && e.ClientMessageEvent.ptr1 == _atom_wm_destroy)
00629 {
00630 Debug.WriteLine("Exit message received.");
00631 CancelEventArgs ce = new CancelEventArgs();
00632 if (Closing != null)
00633 Closing(this, ce);
00634
00635 if (!ce.Cancel)
00636 {
00637 isExiting = true;
00638
00639 Debug.WriteLine("Destroying window.");
00640 using (new XLock(window.Display))
00641 {
00642 Functions.XDestroyWindow(window.Display, window.WindowHandle);
00643 }
00644 break;
00645 }
00646 }
00647
00648 break;
00649
00650 case XEventName.DestroyNotify:
00651 Debug.WriteLine("Window destroyed");
00652 exists = false;
00653
00654 if (Closed != null)
00655 Closed(this, EventArgs.Empty);
00656
00657 return;
00658
00659 case XEventName.ConfigureNotify:
00660 border_width = e.ConfigureEvent.border_width;
00661
00662 Point new_location = new Point(e.ConfigureEvent.x, e.ConfigureEvent.y);
00663 if (Location != new_location)
00664 {
00665 bounds.Location = new_location;
00666 if (Move != null)
00667 Move(this, EventArgs.Empty);
00668 }
00669
00670
00671
00672 Size new_size = new Size(e.ConfigureEvent.width, e.ConfigureEvent.height);
00673 if (ClientSize != new_size)
00674 {
00675 bounds.Size = new_size;
00676 bounds.Width += border_width;
00677 bounds.Height += border_width;
00678
00679
00680 client_rectangle.Size = new_size;
00681
00682 if (this.Resize != null)
00683 Resize(this, EventArgs.Empty);
00684 }
00685 break;
00686
00687 case XEventName.KeyPress:
00688 driver.ProcessEvent(ref e);
00689 int status = 0;
00690 status = Functions.XLookupString(ref e.KeyEvent, ascii, ascii.Length, null, IntPtr.Zero);
00691 Encoding.Default.GetChars(ascii, 0, status, chars, 0);
00692
00693 EventHandler<KeyPressEventArgs> key_press = KeyPress;
00694 if (key_press != null)
00695 {
00696 for (int i = 0; i < status; i++)
00697 {
00698 KPEventArgs.KeyChar = chars[i];
00699 key_press(this, KPEventArgs);
00700 }
00701 }
00702 break;
00703
00704 case XEventName.KeyRelease:
00705
00706
00707
00708 driver.ProcessEvent(ref e);
00709 break;
00710
00711 case XEventName.MotionNotify:
00712 case XEventName.ButtonPress:
00713 case XEventName.ButtonRelease:
00714 driver.ProcessEvent(ref e);
00715 break;
00716
00717 case XEventName.FocusIn:
00718 {
00719 bool previous_focus = has_focus;
00720 has_focus = true;
00721 if (has_focus != previous_focus)
00722 if (FocusedChanged != null)
00723 FocusedChanged(this, EventArgs.Empty);
00724 }
00725 break;
00726
00727 case XEventName.FocusOut:
00728 {
00729 bool previous_focus = has_focus;
00730 has_focus = false;
00731 if (has_focus != previous_focus)
00732 if (FocusedChanged != null)
00733 FocusedChanged(this, EventArgs.Empty);
00734 }
00735 break;
00736
00737 case XEventName.LeaveNotify:
00738 if (MouseLeave != null)
00739 MouseLeave(this, EventArgs.Empty);
00740 break;
00741
00742 case XEventName.EnterNotify:
00743 if (MouseEnter != null)
00744 MouseEnter(this, EventArgs.Empty);
00745 break;
00746
00747 case XEventName.MappingNotify:
00748
00749 if (e.MappingEvent.request == 0 || e.MappingEvent.request == 1)
00750 {
00751 Debug.Print("keybard mapping refreshed");
00752 Functions.XRefreshKeyboardMapping(ref e.MappingEvent);
00753 }
00754 break;
00755
00756 case XEventName.PropertyNotify:
00757 if (e.PropertyEvent.atom == _atom_net_wm_state)
00758 if (WindowStateChanged != null)
00759 WindowStateChanged(this, EventArgs.Empty);
00760 break;
00761
00762 default:
00763
00764 break;
00765 }
00766 }
00767 }
00768
00769 #endregion
00770
00771 #region Bounds
00772
00773 public Rectangle Bounds
00774 {
00775 get { return bounds; }
00776 set
00777 {
00778 using (new XLock(window.Display))
00779 {
00780 Functions.XMoveResizeWindow(window.Display, window.WindowHandle,
00781 value.X, value.Y, value.Width - border_width, value.Height - border_width);
00782 }
00783 }
00784 }
00785
00786 #endregion
00787
00788 #region Location
00789
00790 public Point Location
00791 {
00792 get { return Bounds.Location; }
00793 set
00794 {
00795 using (new XLock(window.Display))
00796 {
00797 Functions.XMoveWindow(window.Display, window.WindowHandle, value.X, value.Y);
00798 }
00799 }
00800 }
00801
00802 #endregion
00803
00804 #region Size
00805
00806 public Size Size
00807 {
00808 get { return Bounds.Size; }
00809 set
00810 {
00811 int width = value.Width - border_width;
00812 int height = value.Height - border_width;
00813 width = width <= 0 ? 1 : width;
00814 height = height <= 0 ? 1 : height;
00815
00816 using (new XLock(window.Display))
00817 {
00818 Functions.XResizeWindow(window.Display, window.WindowHandle, width, height);
00819 }
00820 }
00821 }
00822
00823 #endregion
00824
00825 #region ClientRectangle
00826
00827 public Rectangle ClientRectangle
00828 {
00829 get
00830 {
00831 if (client_rectangle.Width == 0)
00832 client_rectangle.Width = 1;
00833 if (client_rectangle.Height == 0)
00834 client_rectangle.Height = 1;
00835 return client_rectangle;
00836 }
00837 set
00838 {
00839 using (new XLock(window.Display))
00840 {
00841 Functions.XResizeWindow(window.Display, window.WindowHandle,
00842 value.Width, value.Height);
00843 }
00844 }
00845 }
00846
00847 #endregion
00848
00849 #region ClientSize
00850
00851 public Size ClientSize
00852 {
00853 get
00854 {
00855 return ClientRectangle.Size;
00856 }
00857 set
00858 {
00859 ClientRectangle = new Rectangle(Point.Empty, value);
00860 }
00861 }
00862
00863 #endregion
00864
00865 #region Width
00866
00867 public int Width
00868 {
00869 get { return ClientSize.Width; }
00870 set { ClientSize = new Size(value, Height); }
00871 }
00872
00873 #endregion
00874
00875 #region Height
00876
00877 public int Height
00878 {
00879 get { return ClientSize.Height; }
00880 set { ClientSize = new Size(Width, value); }
00881 }
00882
00883 #endregion
00884
00885 #region X
00886
00887 public int X
00888 {
00889 get { return Location.X; }
00890 set { Location = new Point(value, Y); }
00891 }
00892
00893 #endregion
00894
00895 #region Y
00896
00897 public int Y
00898 {
00899 get { return Location.Y; }
00900 set { Location = new Point(X, value); }
00901 }
00902
00903 #endregion
00904
00905 #region Icon
00906
00907 public Icon Icon
00908 {
00909 get
00910 {
00911 return icon;
00912 }
00913 set
00914 {
00915 if (value == icon)
00916 return;
00917
00918
00919
00920 if (value == null)
00921 {
00922 using (new XLock(window.Display))
00923 {
00924 Functions.XDeleteProperty(window.Display, window.WindowHandle, _atom_net_wm_icon);
00925 DeleteIconPixmaps(window.Display, window.WindowHandle);
00926 }
00927 }
00928 else
00929 {
00930
00931 System.Drawing.Bitmap bitmap = value.ToBitmap();
00932 int size = bitmap.Width * bitmap.Height + 2;
00933 IntPtr[] data = new IntPtr[size];
00934 int index = 0;
00935
00936 data[index++] = (IntPtr)bitmap.Width;
00937 data[index++] = (IntPtr)bitmap.Height;
00938
00939 for (int y = 0; y < bitmap.Height; y++)
00940 for (int x = 0; x < bitmap.Width; x++)
00941 data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb();
00942
00943 using (new XLock(window.Display))
00944 {
00945 Functions.XChangeProperty(window.Display, window.WindowHandle,
00946 _atom_net_wm_icon, _atom_xa_cardinal, 32,
00947 PropertyMode.Replace, data, size);
00948 }
00949
00950
00951 DeleteIconPixmaps(window.Display, window.WindowHandle);
00952 using (new XLock(window.Display))
00953 {
00954 IntPtr wmHints_ptr = Functions.XGetWMHints(window.Display, window.WindowHandle);
00955
00956 if (wmHints_ptr == IntPtr.Zero)
00957 wmHints_ptr = Functions.XAllocWMHints();
00958
00959 XWMHints wmHints = (XWMHints)Marshal.PtrToStructure(wmHints_ptr, typeof(XWMHints));
00960
00961 wmHints.flags = new IntPtr(wmHints.flags.ToInt32() | (int)(XWMHintsFlags.IconPixmapHint | XWMHintsFlags.IconMaskHint));
00962 wmHints.icon_pixmap = Functions.CreatePixmapFromImage(window.Display, bitmap);
00963 wmHints.icon_mask = Functions.CreateMaskFromImage(window.Display, bitmap);
00964
00965 Functions.XSetWMHints(window.Display, window.WindowHandle, ref wmHints);
00966 Functions.XFree (wmHints_ptr);
00967
00968 Functions.XSync(window.Display, false);
00969 }
00970 }
00971
00972 icon = value;
00973 if (IconChanged != null)
00974 IconChanged(this, EventArgs.Empty);
00975 }
00976 }
00977
00978 #endregion
00979
00980 #region Focused
00981
00982 public bool Focused
00983 {
00984 get
00985 {
00986 return has_focus;
00987 }
00988 }
00989
00990 #endregion
00991
00992 #region WindowState
00993
00994 public OpenTK.WindowState WindowState
00995 {
00996 get
00997 {
00998 IntPtr actual_atom;
00999 int actual_format;
01000 IntPtr nitems;
01001 IntPtr bytes_after;
01002 IntPtr prop = IntPtr.Zero;
01003 IntPtr atom;
01004
01005 bool fullscreen = false;
01006 int maximized = 0;
01007 bool minimized = false;
01008
01009 using (new XLock(window.Display))
01010 {
01011 Functions.XGetWindowProperty(window.Display, window.WindowHandle,
01012 _atom_net_wm_state, IntPtr.Zero, new IntPtr(256), false,
01013 new IntPtr(4) , out actual_atom, out actual_format,
01014 out nitems, out bytes_after, ref prop);
01015 }
01016
01017 if ((long)nitems > 0 && prop != IntPtr.Zero)
01018 {
01019 for (int i = 0; i < (long)nitems; i++)
01020 {
01021 atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size);
01022
01023 if (atom == _atom_net_wm_state_maximized_horizontal ||
01024 atom == _atom_net_wm_state_maximized_vertical)
01025 maximized++;
01026 else if (atom == _atom_net_wm_state_minimized)
01027 minimized = true;
01028 else if (atom == _atom_net_wm_state_fullscreen)
01029 fullscreen = true;
01030 }
01031 using (new XLock(window.Display))
01032 {
01033 Functions.XFree(prop);
01034 }
01035 }
01036
01037 if (minimized)
01038 return OpenTK.WindowState.Minimized;
01039 else if (maximized == 2)
01040 return OpenTK.WindowState.Maximized;
01041 else if (fullscreen)
01042 return OpenTK.WindowState.Fullscreen;
01043
01044
01045
01046
01047
01048
01049 return OpenTK.WindowState.Normal;
01050 }
01051 set
01052 {
01053 OpenTK.WindowState current_state = this.WindowState;
01054
01055 if (current_state == value)
01056 return;
01057
01058 Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.WindowHandle.ToString(),
01059 current_state.ToString(), value.ToString());
01060
01061 using (new XLock(window.Display))
01062 {
01063
01064 if (current_state == OpenTK.WindowState.Minimized)
01065 Functions.XMapWindow(window.Display, window.WindowHandle);
01066 else if (current_state == OpenTK.WindowState.Fullscreen)
01067 Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove,
01068 _atom_net_wm_state_fullscreen,
01069 IntPtr.Zero);
01070 else if (current_state == OpenTK.WindowState.Maximized)
01071 Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle,
01072 _atom_net_wm_state_maximized_horizontal,
01073 _atom_net_wm_state_maximized_vertical);
01074
01075 Functions.XSync(window.Display, false);
01076 }
01077
01078 bool temporary_resizable = false;
01079 WindowBorder previous_state = WindowBorder;
01080 if (WindowBorder != WindowBorder.Resizable)
01081 {
01082 temporary_resizable = true;
01083 WindowBorder = WindowBorder.Resizable;
01084 }
01085
01086 using (new XLock(window.Display))
01087 {
01088 switch (value)
01089 {
01090 case OpenTK.WindowState.Normal:
01091 Functions.XRaiseWindow(window.Display, window.WindowHandle);
01092
01093 break;
01094
01095 case OpenTK.WindowState.Maximized:
01096 Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
01097 _atom_net_wm_state_maximized_horizontal,
01098 _atom_net_wm_state_maximized_vertical);
01099 Functions.XRaiseWindow(window.Display, window.WindowHandle);
01100
01101 break;
01102
01103 case OpenTK.WindowState.Minimized:
01104
01105 Functions.XIconifyWindow(window.Display, window.WindowHandle, window.Screen);
01106
01107 break;
01108
01109 case OpenTK.WindowState.Fullscreen:
01110
01111
01112 Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
01113 _atom_net_wm_state_fullscreen, IntPtr.Zero);
01114 Functions.XRaiseWindow(window.Display, window.WindowHandle);
01115
01116 break;
01117 }
01118 }
01119
01120 if (temporary_resizable)
01121 WindowBorder = previous_state;
01122 }
01123 }
01124
01125 #endregion
01126
01127 #region WindowBorder
01128
01129 public OpenTK.WindowBorder WindowBorder
01130 {
01131 get
01132 {
01133 if (IsWindowBorderHidden)
01134 return WindowBorder.Hidden;
01135
01136 if (IsWindowBorderResizable)
01137 return WindowBorder.Resizable;
01138 else
01139 return WindowBorder.Fixed;
01140 }
01141 set
01142 {
01143 if (WindowBorder == value)
01144 return;
01145
01146 if (WindowBorder == WindowBorder.Hidden)
01147 EnableWindowDecorations();
01148
01149 switch (value)
01150 {
01151 case WindowBorder.Fixed:
01152 Debug.Print("Making WindowBorder fixed.");
01153 SetWindowMinMax((short)Width, (short)Height, (short)Width, (short)Height);
01154
01155 break;
01156
01157 case WindowBorder.Resizable:
01158 Debug.Print("Making WindowBorder resizable.");
01159 SetWindowMinMax(_min_width, _min_height, -1, -1);
01160
01161 break;
01162
01163 case WindowBorder.Hidden:
01164 Debug.Print("Making WindowBorder hidden.");
01165 DisableWindowDecorations();
01166
01167 break;
01168 }
01169
01170 if (WindowBorderChanged != null)
01171 WindowBorderChanged(this, EventArgs.Empty);
01172 }
01173 }
01174
01175 #endregion
01176
01177 #region Events
01178
01179 public event EventHandler<EventArgs> Load;
01180
01181 public event EventHandler<EventArgs> Unload;
01182
01183 public event EventHandler<EventArgs> Move;
01184
01185 public event EventHandler<EventArgs> Resize;
01186
01187 public event EventHandler<System.ComponentModel.CancelEventArgs> Closing;
01188
01189 public event EventHandler<EventArgs> Closed;
01190
01191 public event EventHandler<EventArgs> Disposed;
01192
01193 public event EventHandler<EventArgs> IconChanged;
01194
01195 public event EventHandler<EventArgs> TitleChanged;
01196
01197 public event EventHandler<EventArgs> VisibleChanged;
01198
01199 public event EventHandler<EventArgs> FocusedChanged;
01200
01201 public event EventHandler<EventArgs> WindowBorderChanged;
01202
01203 public event EventHandler<EventArgs> WindowStateChanged;
01204
01205 public event EventHandler<KeyPressEventArgs> KeyPress;
01206
01207 public event EventHandler<EventArgs> MouseEnter;
01208
01209 public event EventHandler<EventArgs> MouseLeave;
01210
01211 #endregion
01212
01213 #endregion
01214
01215 #region --- INativeGLWindow Members ---
01216
01217 #region public IInputDriver InputDriver
01218
01219 public IInputDriver InputDriver
01220 {
01221 get
01222 {
01223 return driver;
01224 }
01225 }
01226
01227 #endregion
01228
01229 #region public bool Exists
01230
01234 public bool Exists
01235 {
01236 get { return exists; }
01237 }
01238
01239 #endregion
01240
01241 #region public bool IsIdle
01242
01243 public bool IsIdle
01244 {
01245 get { throw new Exception("The method or operation is not implemented."); }
01246 }
01247
01248 #endregion
01249
01250 #region public IntPtr Handle
01251
01255 public IntPtr Handle
01256 {
01257 get { return this.window.WindowHandle; }
01258 }
01259
01260 #endregion
01261
01262 #region public string Title
01263
01268 public string Title
01269 {
01270 get
01271 {
01272 IntPtr name = IntPtr.Zero;
01273 using (new XLock(window.Display))
01274 {
01275 Functions.XFetchName(window.Display, window.WindowHandle, ref name);
01276 }
01277 if (name != IntPtr.Zero)
01278 return Marshal.PtrToStringAnsi(name);
01279
01280 return String.Empty;
01281 }
01282 set
01283 {
01284 if (value != null && value != Title)
01285 {
01286 using (new XLock(window.Display))
01287 {
01288 Functions.XStoreName(window.Display, window.WindowHandle, value);
01289 }
01290 }
01291
01292 if (TitleChanged != null)
01293 TitleChanged(this, EventArgs.Empty);
01294 }
01295 }
01296
01297 #endregion
01298
01299 #region public bool Visible
01300
01301 public bool Visible
01302 {
01303 get
01304 {
01305 return visible;
01306 }
01307 set
01308 {
01309 if (value && !visible)
01310 {
01311 using (new XLock(window.Display))
01312 {
01313 Functions.XMapWindow(window.Display, window.WindowHandle);
01314 }
01315 }
01316 else if (!value && visible)
01317 {
01318 using (new XLock(window.Display))
01319 {
01320 Functions.XUnmapWindow(window.Display, window.WindowHandle);
01321 }
01322 }
01323 }
01324 }
01325
01326 #endregion
01327
01328 #region public IWindowInfo WindowInfo
01329
01330 public IWindowInfo WindowInfo
01331 {
01332 get { return window; }
01333 }
01334
01335 #endregion
01336
01337 public void Close() { Exit(); }
01338
01339 #region public void Exit()
01340
01341 public void Exit()
01342 {
01343 XEvent ev = new XEvent();
01344 ev.type = XEventName.ClientMessage;
01345 ev.ClientMessageEvent.format = 32;
01346 ev.ClientMessageEvent.display = window.Display;
01347 ev.ClientMessageEvent.window = window.WindowHandle;
01348 ev.ClientMessageEvent.ptr1 = _atom_wm_destroy;
01349 using (new XLock(window.Display))
01350 {
01351 Functions.XSendEvent(window.Display, window.WindowHandle, false,
01352 EventMask.NoEventMask, ref ev);
01353 Functions.XFlush(window.Display);
01354 }
01355 }
01356
01357 #endregion
01358
01359 #region public void DestroyWindow()
01360
01361 public void DestroyWindow()
01362 {
01363 Debug.WriteLine("X11GLNative shutdown sequence initiated.");
01364 using (new XLock(window.Display))
01365 {
01366 Functions.XDestroyWindow(window.Display, window.WindowHandle);
01367 }
01368 }
01369
01370 #endregion
01371
01372 #region PointToClient
01373
01374 public Point PointToClient(Point point)
01375 {
01376 int ox, oy;
01377 IntPtr child;
01378
01379 using (new XLock(window.Display))
01380 {
01381 Functions.XTranslateCoordinates(window.Display, window.RootWindow, window.WindowHandle, point.X, point.Y, out ox, out oy, out child);
01382 }
01383
01384 point.X = ox;
01385 point.Y = oy;
01386
01387 return point;
01388 }
01389
01390 #endregion
01391
01392 #region PointToScreen
01393
01394 public Point PointToScreen(Point point)
01395 {
01396 int ox, oy;
01397 IntPtr child;
01398
01399 using (new XLock(window.Display))
01400 {
01401 Functions.XTranslateCoordinates(window.Display, window.WindowHandle, window.RootWindow, point.X, point.Y, out ox, out oy, out child);
01402 }
01403
01404 point.X = ox;
01405 point.Y = oy;
01406
01407 return point;
01408 }
01409
01410 #endregion
01411
01412 #endregion
01413
01414 #region IDisposable Members
01415
01416 public void Dispose()
01417 {
01418 this.Dispose(true);
01419 GC.SuppressFinalize(this);
01420 }
01421
01422 private void Dispose(bool manuallyCalled)
01423 {
01424 if (!disposed)
01425 {
01426 if (manuallyCalled)
01427 {
01428 if (window != null && window.WindowHandle != IntPtr.Zero)
01429 {
01430 if (Exists)
01431 {
01432 using (new XLock(window.Display))
01433 {
01434 Functions.XDestroyWindow(window.Display, window.WindowHandle);
01435 }
01436
01437 while (Exists)
01438 ProcessEvents();
01439 }
01440
01441 window.Dispose();
01442 window = null;
01443 }
01444 }
01445 else
01446 {
01447 Debug.Print("[Warning] {0} leaked.", this.GetType().Name);
01448 }
01449 disposed = true;
01450 }
01451 }
01452
01453 ~X11GLNative()
01454 {
01455 this.Dispose(false);
01456 }
01457
01458 #endregion
01459 }
01460 }