* Platform/X11/X11GraphicsMode.cs, Platform/X11/X11GLNative.cs,

Platform/X11/Structs.cs, Platform/X11/Functions.cs,
  Platform/X11/API.cs: Working on WindowBorder and WindowState
  support.
This commit is contained in:
the_fiddler 2008-05-03 16:33:00 +00:00
parent cedb2394ff
commit a5455cc4e7
5 changed files with 383 additions and 208 deletions

View file

@ -86,9 +86,9 @@ namespace OpenTK.Platform.X11
screenCount = Functions.XScreenCount(DefaultDisplay); screenCount = Functions.XScreenCount(DefaultDisplay);
//Debug.Print("Default Display: {0}, Default Screen: {1}, Default Root Window: {2}, Screen Count: {3}", //Debug.Print("Default Display: {0}, Default Screen: {1}, Default Root Window: {2}, Screen Count: {3}",
// DefaultDisplay, DefaultScreen, RootWindow, ScreenCount); // DefaultDisplay, DefaultScreen, RootWindow, ScreenCount);
Debug.Print("Display connection: {0}, Screen count: {1}", DefaultDisplay, ScreenCount); Debug.Print("Display connection: {0}, Screen count: {1}", DefaultDisplay, ScreenCount);
} }
static void CurrentDomain_ProcessExit(object sender, EventArgs e) static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{ {
if (defaultDisplay != IntPtr.Zero) if (defaultDisplay != IntPtr.Zero)
@ -288,7 +288,7 @@ namespace OpenTK.Platform.X11
/// <para>The X server arbitrarily chooses the keysyms_per_keycode_return value to be large enough to report all requested symbols. A special KeySym value of NoSymbol is used to fill in unused elements for individual KeyCodes. To free the storage returned by XGetKeyboardMapping(), use XFree(). </para> /// <para>The X server arbitrarily chooses the keysyms_per_keycode_return value to be large enough to report all requested symbols. A special KeySym value of NoSymbol is used to fill in unused elements for individual KeyCodes. To free the storage returned by XGetKeyboardMapping(), use XFree(). </para>
/// <para>XGetKeyboardMapping() can generate a BadValue error.</para> /// <para>XGetKeyboardMapping() can generate a BadValue error.</para>
/// <para>Diagnostics:</para> /// <para>Diagnostics:</para>
/// <para>BadValue: Some numeric value falls outside the range of values accepted by the request. Unless a specific range is specified for an argument, the full range defined by the argument's type is accepted. Any argument defined as a set of alternatives can generate this error.</para> /// <para>BadValue: Some numeric value falls outside the range of values accepted by the request. Unless a specific range is specified for an argument, the full range defined by the argument's type is accepted. Any argument defined as a set of alternatives can generate this error.</para>
/// </remarks> /// </remarks>
[DllImport(_dll_name, EntryPoint = "XGetKeyboardMapping")] [DllImport(_dll_name, EntryPoint = "XGetKeyboardMapping")]
public static extern KeySym GetKeyboardMapping(Display display, KeyCode first_keycode, int keycode_count, public static extern KeySym GetKeyboardMapping(Display display, KeyCode first_keycode, int keycode_count,
@ -718,23 +718,23 @@ XF86VidModeGetGammaRampSize(
unsafe internal struct Screen unsafe internal struct Screen
{ {
XExtData ext_data; /* hook for extension to hang buffer */ XExtData ext_data; /* hook for extension to hang buffer */
IntPtr display; /* back pointer to display structure */ /* _XDisplay */ IntPtr display; /* back pointer to display structure */ /* _XDisplay */
Window root; /* Root window id. */ Window root; /* Root window id. */
int width, height; /* width and height of screen */ int width, height; /* width and height of screen */
int mwidth, mheight; /* width and height of in millimeters */ int mwidth, mheight; /* width and height of in millimeters */
int ndepths; /* number of depths possible */ int ndepths; /* number of depths possible */
//Depth *depths; /* list of allowable depths on the screen */ //Depth *depths; /* list of allowable depths on the screen */
int root_depth; /* bits per pixel */ int root_depth; /* bits per pixel */
//Visual* root_visual; /* root visual */ //Visual* root_visual; /* root visual */
IntPtr default_gc; /* GC for the root root visual */ // GC IntPtr default_gc; /* GC for the root root visual */ // GC
Colormap cmap; /* default color map */ Colormap cmap; /* default color map */
UIntPtr white_pixel; // unsigned long UIntPtr white_pixel; // unsigned long
UIntPtr black_pixel; /* White and Black pixel values */ // unsigned long UIntPtr black_pixel; /* White and Black pixel values */ // unsigned long
int max_maps, min_maps; /* max and min color maps */ int max_maps, min_maps; /* max and min color maps */
int backing_store; /* Never, WhenMapped, Always */ int backing_store; /* Never, WhenMapped, Always */
Bool save_unders; Bool save_unders;
long root_input_mask; /* initial root input mask */ long root_input_mask; /* initial root input mask */
} }
#pragma warning restore 0169 #pragma warning restore 0169
@ -743,19 +743,78 @@ XF86VidModeGetGammaRampSize(
#region unsafe internal class XExtData #region unsafe internal class XExtData
#pragma warning disable 0169
unsafe internal class XExtData unsafe internal class XExtData
{ {
int number; /* number returned by XRegisterExtension */ int number; /* number returned by XRegisterExtension */
XExtData next; /* next item on list of buffer for structure */ XExtData next; /* next item on list of buffer for structure */
delegate int FreePrivateDelegate(XExtData extension); delegate int FreePrivateDelegate(XExtData extension);
FreePrivateDelegate FreePrivate; /* called to free private storage */ FreePrivateDelegate FreePrivate; /* called to free private storage */
XPointer private_data; /* buffer private to this extension. */ XPointer private_data; /* buffer private to this extension. */
}; };
#pragma warning restore 0169 #pragma warning restore 0169, 0649
#endregion
#region Motif
[StructLayout(LayoutKind.Sequential)]
internal struct MotifWmHints
{
internal IntPtr flags;
internal IntPtr functions;
internal IntPtr decorations;
internal IntPtr input_mode;
internal IntPtr status;
public override string ToString ()
{
return string.Format("MotifWmHints <flags={0}, functions={1}, decorations={2}, input_mode={3}, status={4}", (MotifFlags) flags.ToInt32 (), (MotifFunctions) functions.ToInt32 (), (MotifDecorations) decorations.ToInt32 (), (MotifInputMode) input_mode.ToInt32 (), status.ToInt32 ());
}
}
[Flags]
internal enum MotifFlags
{
Functions = 1,
Decorations = 2,
InputMode = 4,
Status = 8
}
[Flags]
internal enum MotifFunctions
{
All = 0x01,
Resize = 0x02,
Move = 0x04,
Minimize = 0x08,
Maximize = 0x10,
Close = 0x20
}
[Flags]
internal enum MotifDecorations
{
All = 0x01,
Border = 0x02,
ResizeH = 0x04,
Title = 0x08,
Menu = 0x10,
Minimize = 0x20,
Maximize = 0x40,
}
[Flags]
internal enum MotifInputMode
{
Modeless = 0,
ApplicationModal = 1,
SystemModal = 2,
FullApplicationModal = 3
}
#endregion #endregion
#endregion #endregion
@ -768,7 +827,7 @@ XF86VidModeGetGammaRampSize(
public const int QueuedAfterReading = 1; public const int QueuedAfterReading = 1;
public const int QueuedAfterFlush = 2; public const int QueuedAfterFlush = 2;
public const int CopyFromParent = 0; public const int CopyFromParent = 0;
public const int CWX = 1; public const int CWX = 1;
public const int InputOutput = 1; public const int InputOutput = 1;
public const int InputOnly = 2; public const int InputOnly = 2;
@ -850,28 +909,28 @@ XF86VidModeGetGammaRampSize(
[Flags] [Flags]
public enum CreateWindowMask : long//: ulong public enum CreateWindowMask : long//: ulong
{ {
CWBackPixmap = (1L<<0), CWBackPixmap = (1L<<0),
CWBackPixel = (1L<<1), CWBackPixel = (1L<<1),
CWSaveUnder = (1L<<10), CWSaveUnder = (1L<<10),
CWEventMask = (1L<<11), CWEventMask = (1L<<11),
CWDontPropagate = (1L<<12), CWDontPropagate = (1L<<12),
CWColormap = (1L<<13), CWColormap = (1L<<13),
CWCursor = (1L<<14), CWCursor = (1L<<14),
CWBorderPixmap = (1L<<2), CWBorderPixmap = (1L<<2),
CWBorderPixel = (1L<<3), CWBorderPixel = (1L<<3),
CWBitGravity = (1L<<4), CWBitGravity = (1L<<4),
CWWinGravity = (1L<<5), CWWinGravity = (1L<<5),
CWBackingStore = (1L<<6), CWBackingStore = (1L<<6),
CWBackingPlanes = (1L<<7), CWBackingPlanes = (1L<<7),
CWBackingPixel = (1L<<8), CWBackingPixel = (1L<<8),
CWOverrideRedirect = (1L<<9), CWOverrideRedirect = (1L<<9),
//CWY = (1<<1), //CWY = (1<<1),
//CWWidth = (1<<2), //CWWidth = (1<<2),
//CWHeight = (1<<3), //CWHeight = (1<<3),
//CWBorderWidth = (1<<4), //CWBorderWidth = (1<<4),
//CWSibling = (1<<5), //CWSibling = (1<<5),
//CWStackMode = (1<<6), //CWStackMode = (1<<6),
} }
#region XKey #region XKey
@ -1299,7 +1358,7 @@ XF86VidModeGetGammaRampSize(
[DllImport(X11Library)] [DllImport(X11Library)]
internal static extern void XChangeWindowAttributes(Display display, Window w, UIntPtr valuemask, ref XSetWindowAttributes attributes); internal static extern void XChangeWindowAttributes(Display display, Window w, UIntPtr valuemask, ref XSetWindowAttributes attributes);
internal static void XChangeWindowAttributes(Display display, Window w, ChangeWindowAttributes valuemask, ref XSetWindowAttributes attributes) internal static void XChangeWindowAttributes(Display display, Window w, SetWindowValuemask valuemask, ref XSetWindowAttributes attributes)
{ {
XChangeWindowAttributes(display, w, (UIntPtr)valuemask, ref attributes); XChangeWindowAttributes(display, w, (UIntPtr)valuemask, ref attributes);
} }

View file

@ -418,6 +418,14 @@ namespace OpenTK.Platform.X11
[DllImport("libX11")] [DllImport("libX11")]
public static extern void XUnlockDisplay(Display display); public static extern void XUnlockDisplay(Display display);
[DllImport("libX11")]
public static extern Status XGetTransientForHint(Display display, Window w, out Window prop_window_return);
[DllImport("libX11")]
public static extern void XSync(Display display, bool discard);
public static void SendNetWMMessage(X11WindowInfo window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2) public static void SendNetWMMessage(X11WindowInfo window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
{ {

View file

@ -1073,63 +1073,6 @@ namespace OpenTK.Platform.X11
NotifyDetailNone = 7 NotifyDetailNone = 7
} }
[StructLayout(LayoutKind.Sequential)]
public struct MotifWmHints
{
public IntPtr flags;
public IntPtr functions;
public IntPtr decorations;
public IntPtr input_mode;
public IntPtr status;
public override string ToString()
{
return string.Format("MotifWmHints <flags={0}, functions={1}, decorations={2}, input_mode={3}, status={4}", (MotifFlags)flags.ToInt32(), (MotifFunctions)functions.ToInt32(), (MotifDecorations)decorations.ToInt32(), (MotifInputMode)input_mode.ToInt32(), status.ToInt32());
}
}
[Flags]
public enum MotifFlags
{
Functions = 1,
Decorations = 2,
InputMode = 4,
Status = 8
}
[Flags]
public enum MotifFunctions
{
All = 0x01,
Resize = 0x02,
Move = 0x04,
Minimize = 0x08,
Maximize = 0x10,
Close = 0x20
}
[Flags]
public enum MotifDecorations
{
All = 0x01,
Border = 0x02,
ResizeH = 0x04,
Title = 0x08,
Menu = 0x10,
Minimize = 0x20,
Maximize = 0x40,
}
[Flags]
public enum MotifInputMode
{
Modeless = 0,
ApplicationModal = 1,
SystemModal = 2,
FullApplicationModal = 3
}
[Flags] [Flags]
public enum KeyMasks public enum KeyMasks
{ {

View file

@ -32,26 +32,42 @@ namespace OpenTK.Platform.X11
// TODO: Mouse/keyboard grabbing/wrapping. // TODO: Mouse/keyboard grabbing/wrapping.
// TODO: PointToWindow, PointToScreen // TODO: PointToWindow, PointToScreen
#region --- Fields --- #region --- Fields ---
const int _min_width = 30, _min_height = 30;
X11WindowInfo window = new X11WindowInfo(); X11WindowInfo window = new X11WindowInfo();
X11Input driver; X11Input driver;
// Window manager hints for fullscreen windows. // Window manager hints for fullscreen windows.
// Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which
// are not ICCM compliant, but may support MOTIF hints.
const string MOTIF_WM_ATOM = "_MOTIF_WM_HINTS"; const string MOTIF_WM_ATOM = "_MOTIF_WM_HINTS";
const string KDE_WM_ATOM = "KWM_WIN_DECORATION"; const string KDE_WM_ATOM = "KWM_WIN_DECORATION";
const string KDE_NET_WM_ATOM = "_KDE_NET_WM_WINDOW_TYPE"; const string KDE_NET_WM_ATOM = "_KDE_NET_WM_WINDOW_TYPE";
const string ICCM_WM_ATOM = "_NET_WM_WINDOW_TYPE"; const string ICCM_WM_ATOM = "_NET_WM_WINDOW_TYPE";
IntPtr _atom_wm_state; // The Atom class from Mono might be useful to avoid calling XInternAtom by hand (somewhat error prone).
IntPtr _atom_wm_state_minimized; IntPtr _atom_wm_destroy;
IntPtr _atom_wm_state_fullscreen;
IntPtr _atom_wm_state_maximized_horizontal;
IntPtr _atom_wm_state_maximized_vertical;
static readonly IntPtr _atom_state_remove = (IntPtr)0; IntPtr _atom_net_wm_state;
static readonly IntPtr _atom_state_add = (IntPtr)1; IntPtr _atom_net_wm_state_minimized;
static readonly IntPtr _atom_state_toggle = (IntPtr)2; IntPtr _atom_net_wm_state_fullscreen;
IntPtr _atom_net_wm_state_maximized_horizontal;
IntPtr _atom_net_wm_state_maximized_vertical;
IntPtr _atom_net_wm_allowed_actions;
IntPtr _atom_net_wm_action_resize;
IntPtr _atom_net_wm_action_maximize_horizontally;
IntPtr _atom_net_wm_action_maximize_vertically;
IntPtr _atom_motif_wm_hints;
IntPtr _atom_kde_wm_hints;
IntPtr _atom_kde_net_wm_hints;
static readonly IntPtr _atom_remove = (IntPtr)0;
static readonly IntPtr _atom_add = (IntPtr)1;
static readonly IntPtr _atom_toggle = (IntPtr)2;
// Number of pending events. // Number of pending events.
int pending = 0; int pending = 0;
@ -77,8 +93,10 @@ namespace OpenTK.Platform.X11
int pre_fullscreen_width, pre_fullscreen_height; int pre_fullscreen_width, pre_fullscreen_height;
//bool fullscreen = false; //bool fullscreen = false;
OpenTK.WindowState _window_state, _previous_window_state; bool _decorations_hidden = false;
OpenTK.WindowBorder _window_border, _previous_window_border;
//OpenTK.WindowState _window_state, _previous_window_state;
//OpenTK.WindowBorder _window_border, _previous_window_border;
#endregion #endregion
@ -144,16 +162,26 @@ namespace OpenTK.Platform.X11
/// </summary> /// </summary>
private void RegisterAtoms(X11WindowInfo window) private void RegisterAtoms(X11WindowInfo window)
{ {
Debug.WriteLine("Registering atoms."); Debug.WriteLine("Registering atoms.");
_atom_wm_destroy = Functions.XInternAtom(window.Display, "WM_DELETE_WINDOW", true);
_atom_wm_state = Functions.XInternAtom(window.Display, "_NET_WM_STATE", false); _atom_net_wm_state = Functions.XInternAtom(window.Display, "_NET_WM_STATE", false);
_atom_wm_state_minimized = Functions.XInternAtom(window.Display, "_NET_WM_STATE_MINIMIZED", false); _atom_net_wm_state_minimized = Functions.XInternAtom(window.Display, "_NET_WM_STATE_MINIMIZED", false);
_atom_wm_state_fullscreen = Functions.XInternAtom(window.Display, "_NET_WM_STATE_FULLSCREEN", false); _atom_net_wm_state_fullscreen = Functions.XInternAtom(window.Display, "_NET_WM_STATE_FULLSCREEN", false);
_atom_wm_state_maximized_horizontal = _atom_net_wm_state_maximized_horizontal =
Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_HORZ", false); Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_HORZ", false);
_atom_wm_state_maximized_vertical = _atom_net_wm_state_maximized_vertical =
Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_VERT", false); Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_VERT", false);
_atom_net_wm_allowed_actions =
Functions.XInternAtom(window.Display, "_NET_WM_ALLOWED_ACTIONS", false);
_atom_net_wm_action_resize =
Functions.XInternAtom(window.Display, "_NET_WM_ACTION_RESIZE", false);
_atom_net_wm_action_maximize_horizontally =
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);
// string[] atom_names = new string[] // string[] atom_names = new string[]
// { // {
// //"WM_TITLE", // //"WM_TITLE",
@ -218,20 +246,21 @@ namespace OpenTK.Platform.X11
} }
context = new GraphicsContext(mode, window); context = new GraphicsContext(mode, window);
// Set the window hints // Set the window hints
SetWindowMinMax(_min_width, _min_height, -1, -1);
XSizeHints hints = new XSizeHints(); XSizeHints hints = new XSizeHints();
hints.x = 0; hints.x = 0;
hints.y = 0; hints.y = 0;
hints.width = width; hints.width = width;
hints.height = height; hints.height = height;
hints.flags = (IntPtr)(XSizeHintsFlags.USSize | XSizeHintsFlags.USPosition); hints.flags = (IntPtr)(XSizeHintsFlags.USSize);// | XSizeHintsFlags.USPosition);
lock (API.Lock) lock (API.Lock)
{ {
Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints); Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints);
// Register for window destroy notification // Register for window destroy notification
IntPtr wm_destroy_atom = Functions.XInternAtom(window.Display, "WM_DELETE_WINDOW", true); Functions.XSetWMProtocols(window.Display, window.WindowHandle, new IntPtr[] { _atom_wm_destroy }, 1);
Functions.XSetWMProtocols(window.Display, window.WindowHandle, new IntPtr[] { wm_destroy_atom }, 1);
} }
Top = Left = 0; Top = Left = 0;
Right = Width; Right = Width;
@ -253,11 +282,22 @@ namespace OpenTK.Platform.X11
//context.CreateContext(true, null); //context.CreateContext(true, null);
driver = new X11Input(window); driver = new X11Input(window);
// HACK: This seems to reduce thread issues on Linux, due to race conditions.
// It does *not* solve the root cause, which is unknown at this point.
//
// What I suspect happens, is that either the glXChooseContext or glXCreateContext functions are called
// before the window is ready - or maybe before the window size is set which renders the viewport invalid?
// (can this happen?) or that there are pending events that somehow botch context creation up (seems like
// the fglrx driver is spawning a new thread, or waiting on something?)
// This issue *must* be resolved before the 1.0 release.
// Note that this has the side effect that sometimes, a resize event is missed.
//Functions.XSync(window.Display, true);
Debug.WriteLine("X11GLNative window created successfully!"); Debug.WriteLine("X11GLNative window created successfully!");
Debug.Unindent(); Debug.Unindent();
exists = true; exists = true;
} }
@ -293,8 +333,13 @@ namespace OpenTK.Platform.X11
// A child was was created - nothing to do // A child was was created - nothing to do
break; break;
case XEventName.ClientMessage: case XEventName.ClientMessage:
this.OnDestroy(EventArgs.Empty); if (e.ClientMessageEvent.ptr1 == _atom_wm_destroy)
this.OnDestroy(EventArgs.Empty);
else
Debug.Print("Niar");
break; break;
case XEventName.DestroyNotify: case XEventName.DestroyNotify:
@ -607,21 +652,21 @@ namespace OpenTK.Platform.X11
bool minimized = false; bool minimized = false;
Functions.XGetWindowProperty(window.Display, window.WindowHandle, Functions.XGetWindowProperty(window.Display, window.WindowHandle,
_atom_wm_state, IntPtr.Zero, new IntPtr (256), false, _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); 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)
{ {
Debug.Print("nitems: {0}", nitems.ToString());
for (int i = 0; i < (long)nitems; i++) for (int i = 0; i < (long)nitems; i++)
{ {
atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size); atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size);
if (atom == _atom_wm_state_maximized_horizontal || atom == _atom_wm_state_maximized_vertical) if (atom == _atom_net_wm_state_maximized_horizontal ||
atom == _atom_net_wm_state_maximized_vertical)
maximized++; maximized++;
else if (atom == _atom_wm_state_minimized) else if (atom == _atom_net_wm_state_minimized)
minimized = true; minimized = true;
else if (atom == _atom_wm_state_fullscreen) else if (atom == _atom_net_wm_state_fullscreen)
fullscreen = true; fullscreen = true;
} }
Functions.XFree(prop); Functions.XFree(prop);
@ -655,15 +700,15 @@ namespace OpenTK.Platform.X11
Functions.XMapWindow(window.Display, window.WindowHandle); Functions.XMapWindow(window.Display, window.WindowHandle);
else if (current_state == OpenTK.WindowState.Fullscreen) else if (current_state == OpenTK.WindowState.Fullscreen)
{ {
WindowBorder = _previous_window_border; //WindowBorder = _previous_window_border;
Functions.SendNetWMMessage(window, _atom_wm_state, _atom_state_remove, Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove,
_atom_wm_state_fullscreen, _atom_net_wm_state_fullscreen,
IntPtr.Zero); IntPtr.Zero);
} }
else if (current_state == OpenTK.WindowState.Maximized) else if (current_state == OpenTK.WindowState.Maximized)
Functions.SendNetWMMessage(window, _atom_wm_state, _atom_state_toggle, Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle,
_atom_wm_state_maximized_horizontal, _atom_net_wm_state_maximized_horizontal,
_atom_wm_state_maximized_vertical); _atom_net_wm_state_maximized_vertical);
switch (value) switch (value)
{ {
@ -673,12 +718,23 @@ namespace OpenTK.Platform.X11
break; break;
case OpenTK.WindowState.Maximized: case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window, _atom_wm_state, _atom_state_add, // We can't resize the window if its border is fixed, so make it resizable first.
_atom_wm_state_maximized_horizontal, bool temporary_resizable = false;
_atom_wm_state_maximized_vertical); if (WindowBorder == WindowBorder.Fixed)
{
temporary_resizable = true;
WindowBorder = WindowBorder.Resizable;
}
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); Functions.XRaiseWindow(window.Display, window.WindowHandle);
if (temporary_resizable)
WindowBorder = WindowBorder.Fixed;
break; break;
case WindowState.Minimized: case WindowState.Minimized:
@ -688,11 +744,11 @@ namespace OpenTK.Platform.X11
break; break;
case WindowState.Fullscreen: case WindowState.Fullscreen:
_previous_window_border = this.WindowBorder; //_previous_window_border = this.WindowBorder;
this.WindowBorder = WindowBorder.Hidden; //this.WindowBorder = WindowBorder.Hidden;
Functions.SendNetWMMessage(window, _atom_wm_state, _atom_state_add, Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_wm_state_fullscreen, IntPtr.Zero); _atom_net_wm_state_fullscreen, IntPtr.Zero);
break; break;
} }
@ -707,18 +763,134 @@ namespace OpenTK.Platform.X11
{ {
get get
{ {
return _window_border; //return _window_border;
IntPtr actual_atom;
int actual_format;
IntPtr nitems;
IntPtr bytes_after;
IntPtr prop = IntPtr.Zero;
IntPtr atom;
XWindowAttributes attributes;
bool resizable = false, hidden = false;
// IntPtr transient; // The window for which X11GLWindow is transient, if any.
//
// Functions.XGetTransientForHint(window.Display, window.WindowHandle, out transient);
// if (transient != IntPtr.Zero)
// return WindowBorder.Hidden;
if (_decorations_hidden)
return WindowBorder.Hidden;
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)
{
for (int i = 0; i < (long)nitems; i++)
{
atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size);
if (atom == _atom_net_wm_action_resize)
resizable = true;
//else if (atom
//return WindowBorder.Resizable;
// if (atom == _atom_wm_state_maximized_horizontal || atom == _atom_wm_state_maximized_vertical)
// maximized++;
// else if (atom == _atom_wm_state_minimized)
// minimized = true;
// else if (atom == _atom_wm_state_fullscreen)
// fullscreen = true;
}
Functions.XFree(prop);
}
if (resizable)
return WindowBorder.Resizable;
else
return WindowBorder.Fixed;
} }
set set
{ {
_window_border = value; if (WindowBorder == value)
//Functions.XChangeProperty(window.Display, window.WindowHandle, return;
if (WindowBorder == WindowBorder.Hidden)
{
EnableWindowDecorations();
// int error = Functions.XSetTransientForHint(window.Display, window.WindowHandle, IntPtr.Zero);
// if (error == 0)
// Debug.Print("Error");
}
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();
//Functions.XSetTransientForHint(window.Display, window.WindowHandle, window.RootWindow);
break;
}
// Functions.SendNetWMMessage(window, _atom_wm_state, _atom_state_add,
// _atom_wm_state_fullscreen, IntPtr.Zero);
} }
} }
#endregion #endregion
#endregion #endregion
void SetWindowMinMax(short min_width, short min_height, short max_width, short max_height)
{
IntPtr dummy;
XSizeHints hints = new XSizeHints();
Functions.XGetWMNormalHints(window.Display, window.WindowHandle, ref hints, out dummy);
if (min_width > 0 || min_height > 0)
{
hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMinSize);
hints.min_width = min_width;
hints.min_height = min_height;
}
else
hints.flags = (IntPtr)((int)hints.flags & ~(int)XSizeHintsFlags.PMinSize);
if (max_width > 0 || max_height > 0)
{
hints.flags = (IntPtr)((int)hints.flags | (int)XSizeHintsFlags.PMaxSize);
hints.max_width = max_width;
hints.max_height = max_height;
}
else
hints.flags = (IntPtr)((int)hints.flags & ~(int)XSizeHintsFlags.PMaxSize);
if (hints.flags != IntPtr.Zero)
{
// The Metacity team has decided that they won't care about this when clicking the maximize
// icon, will maximize the window to fill the screen/parent no matter what.
// http://bugzilla.ximian.com/show_bug.cgi?id=80021
Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints);
}
}
#region --- IResizable Members --- #region --- IResizable Members ---
@ -868,18 +1040,24 @@ namespace OpenTK.Platform.X11
#region void DisableWindowDecorations() #region void DisableWindowDecorations()
void DisableWindowDecorations() void DisableWindowDecorations()
{ {
bool removed = false; if (DisableMotifDecorations())
if (DisableMotifDecorations()) { Debug.Print("Removed decorations through motif."); removed = true; } {
if (DisableGnomeDecorations()) { Debug.Print("Removed decorations through gnome."); removed = true; } Debug.Print("Removed decorations through motif.");
if (DisableIccmDecorations()) { Debug.Print("Removed decorations through ICCM."); removed = true; } _decorations_hidden = true;
}
//bool removed = false;
//if (DisableMotifDecorations()) { Debug.Print("Removed decorations through motif."); removed = true; }
//if (DisableGnomeDecorations()) { Debug.Print("Removed decorations through gnome."); removed = true; }
//if (DisableIccmDecorations()) { Debug.Print("Removed decorations through ICCM."); removed = true; }
if (removed) //if (removed)
{ //{
Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow); // Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow);
Functions.XUnmapWindow(this.window.Display, this.Handle); // Functions.XUnmapWindow(this.window.Display, this.Handle);
Functions.XMapWindow(this.window.Display, this.Handle); // Functions.XMapWindow(this.window.Display, this.Handle);
} //}
} }
#region bool DisableMotifDecorations() #region bool DisableMotifDecorations()
@ -891,8 +1069,8 @@ namespace OpenTK.Platform.X11
{ {
MotifWmHints hints = new MotifWmHints(); MotifWmHints hints = new MotifWmHints();
hints.flags = (IntPtr)MotifFlags.Decorations; hints.flags = (IntPtr)MotifFlags.Decorations;
Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace, ref hints, 5 Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
/*Marshal.SizeOf(hints) / 4*/); ref hints, /*Marshal.SizeOf(hints) / 4*/ 5);
return true; return true;
} }
return false; return false;
@ -904,30 +1082,12 @@ namespace OpenTK.Platform.X11
bool DisableGnomeDecorations() bool DisableGnomeDecorations()
{ {
// Attempt to cover gnome panels.
//XEvent xev = new XEvent();
//xev.ClientMessageEvent.window = this.window.Handle;
//xev.ClientMessageEvent.type = XEventName.ClientMessage;
//xev.ClientMessageEvent.message_type = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_LAYER, false);
//xev.ClientMessageEvent.format = 32;
//xev.ClientMessageEvent.ptr1 = (IntPtr)WindowLayer.AboveDock;
//Functions.XSendEvent(this.window.Display, this.window.RootWindow, false, (IntPtr)EventMask.SubstructureNotifyMask, ref xev);
//xev = new XEvent();
//xev.ClientMessageEvent.window = this.window.Handle;
//xev.ClientMessageEvent.type = XEventName.ClientMessage;
//xev.ClientMessageEvent.message_type = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_STATE, false);
//xev.ClientMessageEvent.format = 32;
//xev.ClientMessageEvent.ptr1 = (IntPtr)WindowState.;
//xev.ClientMessageEvent.ptr2 = (IntPtr)WindowLayer.AboveDock;
//Functions.XSendEvent(this.window.Display, this.window.RootWindow, false, (IntPtr)EventMask.SubstructureNotifyMask, ref xev);
IntPtr atom = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_HINTS, true); IntPtr atom = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_HINTS, true);
if (atom != IntPtr.Zero) if (atom != IntPtr.Zero)
{ {
IntPtr hints = IntPtr.Zero; IntPtr hints = IntPtr.Zero;
Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace, ref hints, Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
/*Marshal.SizeOf(hints) / 4*/ 1); ref hints, /*Marshal.SizeOf(hints) / 4*/ 1);
return true; return true;
} }
@ -944,8 +1104,8 @@ namespace OpenTK.Platform.X11
if (atom != IntPtr.Zero) if (atom != IntPtr.Zero)
{ {
IntPtr hints = Functions.XInternAtom(this.window.Display, "_NET_WM_STATE_FULLSCREEN", true); IntPtr hints = Functions.XInternAtom(this.window.Display, "_NET_WM_STATE_FULLSCREEN", true);
Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace, ref hints, 1 Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
/*Marshal.SizeOf(hints) / 4*/); ref hints, /*Marshal.SizeOf(hints) / 4*/ 1);
return true; return true;
} }
return false; return false;
@ -958,18 +1118,23 @@ namespace OpenTK.Platform.X11
#region void EnableWindowDecorations() #region void EnableWindowDecorations()
void EnableWindowDecorations() void EnableWindowDecorations()
{ {
bool activated = false; if (EnableMotifDecorations())
if (EnableMotifDecorations()) { Debug.Print("Activated decorations through motif."); activated = true; } {
if (EnableGnomeDecorations()) { Debug.Print("Activated decorations through gnome."); activated = true; } Debug.Print("Activated decorations through motif.");
if (EnableIccmDecorations()) { Debug.Print("Activated decorations through ICCM."); activated = true; } _decorations_hidden = false;
}
//bool activated = false;
//if (EnableMotifDecorations()) { Debug.Print("Activated decorations through motif."); activated = true; }
//if (EnableGnomeDecorations()) { Debug.Print("Activated decorations through gnome."); activated = true; }
//if (EnableIccmDecorations()) { Debug.Print("Activated decorations through ICCM."); activated = true; }
if (activated) //if (activated)
{ //{
Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow); // Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow);
Functions.XUnmapWindow(this.window.Display, this.Handle); // Functions.XUnmapWindow(this.window.Display, this.Handle);
Functions.XMapWindow(this.window.Display, this.Handle); // Functions.XMapWindow(this.window.Display, this.Handle);
} //}
} }
#region bool EnableMotifDecorations() #region bool EnableMotifDecorations()
@ -1022,8 +1187,8 @@ namespace OpenTK.Platform.X11
IntPtr hint = Functions.XInternAtom(this.window.Display, "_NET_WM_WINDOW_TYPE_NORMAL", true); IntPtr hint = Functions.XInternAtom(this.window.Display, "_NET_WM_WINDOW_TYPE_NORMAL", true);
if (hint != IntPtr.Zero) if (hint != IntPtr.Zero)
{ {
Functions.XChangeProperty(this.window.Display, this.Handle, hint, /*XA_ATOM*/(IntPtr)4, 32, PropertyMode.Replace, Functions.XChangeProperty(this.window.Display, this.Handle, hint, /*XA_ATOM*/(IntPtr)4, 32,
ref hint, Marshal.SizeOf(hint) / 4); PropertyMode.Replace, hint, Marshal.SizeOf(hint) / 4);
} }
return true; return true;
} }

View file

@ -84,7 +84,7 @@ namespace OpenTK.Platform.X11
try try
{ {
Functions.XLockDisplay(display); //Functions.XLockDisplay(display);
int screen = Functions.XDefaultScreen(display); int screen = Functions.XDefaultScreen(display);
IntPtr root = Functions.XRootWindow(display, screen); IntPtr root = Functions.XRootWindow(display, screen);
@ -122,7 +122,7 @@ namespace OpenTK.Platform.X11
} }
finally finally
{ {
Functions.XUnlockDisplay(display); //Functions.XUnlockDisplay(display);
} }
// Prepare Windows.Forms for creating OpenGL drawables. // Prepare Windows.Forms for creating OpenGL drawables.