Protect all Xlib calls with XLockDisplay/XUnlockDisplay. Fixes issue [#1354]: "Application always run in windowed mode when using shared contexts".

This commit is contained in:
the_fiddler 2009-11-09 19:05:41 +00:00
parent 2cbf60bb6f
commit fdf4a93829
3 changed files with 220 additions and 157 deletions

View file

@ -1590,15 +1590,32 @@ XF86VidModeGetGammaRampSize(
} }
*/ */
// Helper structure for calling XLock/UnlockDisplay
struct XLock : IDisposable struct XLock : IDisposable
{ {
readonly IntPtr Display; IntPtr _display;
public IntPtr Display
{
get
{
if (_display == IntPtr.Zero)
throw new InvalidOperationException("Internal error (XLockDisplay with IntPtr.Zero). Please report this at http://www.opentk.com/node/add/project-issue/opentk");
return _display;
}
set
{
if (value == IntPtr.Zero)
throw new ArgumentException();
_display = value;
}
}
public XLock(IntPtr display) public XLock(IntPtr display)
: this() : this()
{ {
Functions.XLockDisplay(display);
Display = display; Display = display;
Functions.XLockDisplay(Display);
} }
public void Dispose() public void Dispose()

View file

@ -280,7 +280,10 @@ namespace OpenTK.Platform.X11
IntPtr dummy; IntPtr dummy;
XSizeHints hints = new XSizeHints(); XSizeHints hints = new XSizeHints();
Functions.XGetWMNormalHints(window.Display, window.WindowHandle, ref hints, out dummy); using (new XLock(window.Display))
{
Functions.XGetWMNormalHints(window.Display, window.WindowHandle, ref hints, out dummy);
}
if (min_width > 0 || min_height > 0) if (min_width > 0 || min_height > 0)
{ {
@ -300,13 +303,15 @@ namespace OpenTK.Platform.X11
else else
hints.flags = (IntPtr)((int)hints.flags & ~(int)XSizeHintsFlags.PMaxSize); hints.flags = (IntPtr)((int)hints.flags & ~(int)XSizeHintsFlags.PMaxSize);
if (hints.flags != IntPtr.Zero) if (hints.flags != IntPtr.Zero)
{ {
// The Metacity team has decided that they won't care about this when clicking the maximize // 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. // icon, will maximize the window to fill the screen/parent no matter what.
// http://bugzilla.ximian.com/show_bug.cgi?id=80021 // http://bugzilla.ximian.com/show_bug.cgi?id=80021
Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints); using (new XLock(window.Display))
{
Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints);
}
} }
} }
@ -326,20 +331,23 @@ namespace OpenTK.Platform.X11
IntPtr atom; IntPtr atom;
//XWindowAttributes attributes; //XWindowAttributes attributes;
Functions.XGetWindowProperty(window.Display, window.WindowHandle, using (new XLock(window.Display))
_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++) 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)
{ {
atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size); for (int i = 0; i < (long)nitems; i++)
{
atom = (IntPtr)Marshal.ReadIntPtr(prop, i * IntPtr.Size);
if (atom == _atom_net_wm_action_resize) if (atom == _atom_net_wm_action_resize)
return true; return true;
}
Functions.XFree(prop);
} }
Functions.XFree(prop);
} }
return false; return false;
@ -362,24 +370,27 @@ namespace OpenTK.Platform.X11
//IntPtr atom; //IntPtr atom;
//XWindowAttributes attributes; //XWindowAttributes attributes;
// Test if decorations have been disabled through Motif. using (new XLock(window.Display))
IntPtr motif_hints_atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true);
if (motif_hints_atom != IntPtr.Zero)
{ {
// TODO: How to check if MotifWMHints decorations have been really disabled? // Test if decorations have been disabled through Motif.
if (_decorations_hidden) IntPtr motif_hints_atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true);
if (motif_hints_atom != IntPtr.Zero)
{
// TODO: How to check if MotifWMHints decorations have been really disabled?
if (_decorations_hidden)
return true;
}
// Some WMs remove decorations when the transient_for hint is set. Most new ones do not (but those
// should obey the Motif hint). Anyway, if this hint is set, we say the decorations have been remove
// although there is a slight chance this is not the case.
IntPtr transient_for_parent;
Functions.XGetTransientForHint(window.Display, window.WindowHandle, out transient_for_parent);
if (transient_for_parent != IntPtr.Zero)
return true; return true;
return false;
} }
// Some WMs remove decorations when the transient_for hint is set. Most new ones do not (but those
// should obey the Motif hint). Anyway, if this hint is set, we say the decorations have been remove
// although there is a slight chance this is not the case.
IntPtr transient_for_parent;
Functions.XGetTransientForHint(window.Display, window.WindowHandle, out transient_for_parent);
if (transient_for_parent != IntPtr.Zero)
return true;
return false;
} }
} }
@ -395,15 +406,18 @@ namespace OpenTK.Platform.X11
_decorations_hidden = true; _decorations_hidden = true;
} }
// Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow); using (new XLock(window.Display))
// Some WMs remove decorations when this hint is set. Doesn't hurt to try.
Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow);
if (_decorations_hidden)
{ {
Functions.XUnmapWindow(this.window.Display, this.Handle); // Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow);
Functions.XMapWindow(this.window.Display, this.Handle);
// Some WMs remove decorations when this hint is set. Doesn't hurt to try.
Functions.XSetTransientForHint(this.window.Display, this.Handle, this.window.RootWindow);
if (_decorations_hidden)
{
Functions.XUnmapWindow(this.window.Display, this.Handle);
Functions.XMapWindow(this.window.Display, this.Handle);
}
} }
} }
@ -459,12 +473,15 @@ namespace OpenTK.Platform.X11
//if (EnableGnomeDecorations()) { Debug.Print("Activated decorations through gnome."); activated = true; } //if (EnableGnomeDecorations()) { Debug.Print("Activated decorations through gnome."); activated = true; }
Functions.XSetTransientForHint(this.window.Display, this.Handle, IntPtr.Zero); using (new XLock(window.Display))
if (!_decorations_hidden)
{ {
Functions.XUnmapWindow(this.window.Display, this.Handle); Functions.XSetTransientForHint(this.window.Display, this.Handle, IntPtr.Zero);
Functions.XMapWindow(this.window.Display, this.Handle);
if (!_decorations_hidden)
{
Functions.XUnmapWindow(this.window.Display, this.Handle);
Functions.XMapWindow(this.window.Display, this.Handle);
}
} }
} }
@ -472,19 +489,22 @@ namespace OpenTK.Platform.X11
bool EnableMotifDecorations() bool EnableMotifDecorations()
{ {
IntPtr atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true); using (new XLock(window.Display))
if (atom != IntPtr.Zero)
{ {
//Functions.XDeleteProperty(this.window.Display, this.Handle, atom); IntPtr atom = Functions.XInternAtom(this.window.Display, MOTIF_WM_ATOM, true);
MotifWmHints hints = new MotifWmHints(); if (atom != IntPtr.Zero)
hints.flags = (IntPtr)MotifFlags.Decorations; {
hints.decorations = (IntPtr)MotifDecorations.All; //Functions.XDeleteProperty(this.window.Display, this.Handle, atom);
Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace, MotifWmHints hints = new MotifWmHints();
ref hints, Marshal.SizeOf(hints) / IntPtr.Size); hints.flags = (IntPtr)MotifFlags.Decorations;
hints.decorations = (IntPtr)MotifDecorations.All;
Functions.XChangeProperty(this.window.Display, this.Handle, atom, atom, 32, PropertyMode.Replace,
ref hints, Marshal.SizeOf(hints) / IntPtr.Size);
return true; return true;
}
return false;
} }
return false;
} }
#endregion #endregion
@ -493,23 +513,26 @@ namespace OpenTK.Platform.X11
bool EnableGnomeDecorations() bool EnableGnomeDecorations()
{ {
// Restore window layer. using (new XLock(window.Display))
//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);
IntPtr atom = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_HINTS, true);
if (atom != IntPtr.Zero)
{ {
Functions.XDeleteProperty(this.window.Display, this.Handle, atom); // Restore window layer.
return true; //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);
return false; IntPtr atom = Functions.XInternAtom(this.window.Display, Constants.XA_WIN_HINTS, true);
if (atom != IntPtr.Zero)
{
Functions.XDeleteProperty(this.window.Display, this.Handle, atom);
return true;
}
return false;
}
} }
#endregion #endregion
@ -520,27 +543,30 @@ namespace OpenTK.Platform.X11
static void DeleteIconPixmaps(IntPtr display, IntPtr window) static void DeleteIconPixmaps(IntPtr display, IntPtr window)
{ {
IntPtr wmHints_ptr = Functions.XGetWMHints(display, window); using (new XLock(display))
if (wmHints_ptr != IntPtr.Zero)
{ {
XWMHints wmHints = (XWMHints)Marshal.PtrToStructure(wmHints_ptr, typeof(XWMHints)); IntPtr wmHints_ptr = Functions.XGetWMHints(display, window);
XWMHintsFlags flags = (XWMHintsFlags)wmHints.flags.ToInt32();
if ((flags & XWMHintsFlags.IconPixmapHint) != 0) if (wmHints_ptr != IntPtr.Zero)
{ {
wmHints.flags = new IntPtr((int)(flags & ~XWMHintsFlags.IconPixmapHint)); XWMHints wmHints = (XWMHints)Marshal.PtrToStructure(wmHints_ptr, typeof(XWMHints));
Functions.XFreePixmap(display, wmHints.icon_pixmap); XWMHintsFlags flags = (XWMHintsFlags)wmHints.flags.ToInt32();
}
if ((flags & XWMHintsFlags.IconMaskHint) != 0) if ((flags & XWMHintsFlags.IconPixmapHint) != 0)
{ {
wmHints.flags = new IntPtr((int)(flags & ~XWMHintsFlags.IconMaskHint)); wmHints.flags = new IntPtr((int)(flags & ~XWMHintsFlags.IconPixmapHint));
Functions.XFreePixmap(display, wmHints.icon_mask); Functions.XFreePixmap(display, wmHints.icon_pixmap);
} }
Functions.XSetWMHints(display, window, ref wmHints); if ((flags & XWMHintsFlags.IconMaskHint) != 0)
Functions.XFree(wmHints_ptr); {
wmHints.flags = new IntPtr((int)(flags & ~XWMHintsFlags.IconMaskHint));
Functions.XFreePixmap(display, wmHints.icon_mask);
}
Functions.XSetWMHints(display, window, ref wmHints);
Functions.XFree(wmHints_ptr);
}
} }
} }
@ -863,8 +889,11 @@ namespace OpenTK.Platform.X11
// For this reason, we'll also set the icon using XSetWMHints. // For this reason, we'll also set the icon using XSetWMHints.
if (value == null) if (value == null)
{ {
Functions.XDeleteProperty(window.Display, window.WindowHandle, _atom_net_wm_icon); using (new XLock(window.Display))
DeleteIconPixmaps(window.Display, window.WindowHandle); {
Functions.XDeleteProperty(window.Display, window.WindowHandle, _atom_net_wm_icon);
DeleteIconPixmaps(window.Display, window.WindowHandle);
}
} }
else else
{ {
@ -881,27 +910,33 @@ namespace OpenTK.Platform.X11
for (int x = 0; x < bitmap.Width; x++) for (int x = 0; x < bitmap.Width; x++)
data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb(); data[index++] = (IntPtr)bitmap.GetPixel(x, y).ToArgb();
Functions.XChangeProperty(window.Display, window.WindowHandle, using (new XLock(window.Display))
_atom_net_wm_icon, _atom_xa_cardinal, 32, {
PropertyMode.Replace, data, size); Functions.XChangeProperty(window.Display, window.WindowHandle,
_atom_net_wm_icon, _atom_xa_cardinal, 32,
PropertyMode.Replace, data, size);
}
// Set XWMHints // Set XWMHints
DeleteIconPixmaps(window.Display, window.WindowHandle); DeleteIconPixmaps(window.Display, window.WindowHandle);
IntPtr wmHints_ptr = Functions.XGetWMHints(window.Display, window.WindowHandle); using (new XLock(window.Display))
{
IntPtr wmHints_ptr = Functions.XGetWMHints(window.Display, window.WindowHandle);
if (wmHints_ptr == IntPtr.Zero) if (wmHints_ptr == IntPtr.Zero)
wmHints_ptr = Functions.XAllocWMHints(); wmHints_ptr = Functions.XAllocWMHints();
XWMHints wmHints = (XWMHints)Marshal.PtrToStructure(wmHints_ptr, typeof(XWMHints)); XWMHints wmHints = (XWMHints)Marshal.PtrToStructure(wmHints_ptr, typeof(XWMHints));
wmHints.flags = new IntPtr(wmHints.flags.ToInt32() | (int)(XWMHintsFlags.IconPixmapHint | XWMHintsFlags.IconMaskHint)); wmHints.flags = new IntPtr(wmHints.flags.ToInt32() | (int)(XWMHintsFlags.IconPixmapHint | XWMHintsFlags.IconMaskHint));
wmHints.icon_pixmap = Functions.CreatePixmapFromImage(window.Display, bitmap); wmHints.icon_pixmap = Functions.CreatePixmapFromImage(window.Display, bitmap);
wmHints.icon_mask = Functions.CreateMaskFromImage(window.Display, bitmap); wmHints.icon_mask = Functions.CreateMaskFromImage(window.Display, bitmap);
Functions.XSetWMHints(window.Display, window.WindowHandle, ref wmHints); Functions.XSetWMHints(window.Display, window.WindowHandle, ref wmHints);
Functions.XFree (wmHints_ptr); Functions.XFree (wmHints_ptr);
Functions.XSync(window.Display, false); Functions.XSync(window.Display, false);
}
} }
icon = value; icon = value;
@ -941,9 +976,12 @@ namespace OpenTK.Platform.X11
int maximized = 0; int maximized = 0;
bool minimized = false; bool minimized = false;
Functions.XGetWindowProperty(window.Display, window.WindowHandle, using (new XLock(window.Display))
_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); Functions.XGetWindowProperty(window.Display, window.WindowHandle,
_atom_net_wm_state, IntPtr.Zero, new IntPtr(256), false,
IntPtr.Zero, out actual_atom, out actual_format, out nitems, out bytes_after, ref prop);
}
if ((long)nitems > 0 && prop != IntPtr.Zero) if ((long)nitems > 0 && prop != IntPtr.Zero)
{ {
@ -959,7 +997,10 @@ namespace OpenTK.Platform.X11
else if (atom == _atom_net_wm_state_fullscreen) else if (atom == _atom_net_wm_state_fullscreen)
fullscreen = true; fullscreen = true;
} }
Functions.XFree(prop); using (new XLock(window.Display))
{
Functions.XFree(prop);
}
} }
if (minimized) if (minimized)
@ -986,19 +1027,21 @@ namespace OpenTK.Platform.X11
Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.WindowHandle.ToString(), Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.WindowHandle.ToString(),
current_state.ToString(), value.ToString()); current_state.ToString(), value.ToString());
if (current_state == OpenTK.WindowState.Minimized) using (new XLock(window.Display))
Functions.XMapWindow(window.Display, window.WindowHandle); {
else if (current_state == OpenTK.WindowState.Fullscreen) if (current_state == OpenTK.WindowState.Minimized)
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove, Functions.XMapWindow(window.Display, window.WindowHandle);
_atom_net_wm_state_fullscreen, else if (current_state == OpenTK.WindowState.Fullscreen)
IntPtr.Zero); Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove,
else if (current_state == OpenTK.WindowState.Maximized) _atom_net_wm_state_fullscreen,
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle, IntPtr.Zero);
_atom_net_wm_state_maximized_horizontal, else if (current_state == OpenTK.WindowState.Maximized)
_atom_net_wm_state_maximized_vertical); Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle,
_atom_net_wm_state_maximized_horizontal,
Functions.XSync(window.Display, false); _atom_net_wm_state_maximized_vertical);
Functions.XSync(window.Display, false);
}
// We can't resize the window if its border is fixed, so make it resizable first. // We can't resize the window if its border is fixed, so make it resizable first.
bool temporary_resizable = false; bool temporary_resizable = false;
WindowBorder previous_state = WindowBorder; WindowBorder previous_state = WindowBorder;
@ -1008,35 +1051,38 @@ namespace OpenTK.Platform.X11
WindowBorder = WindowBorder.Resizable; WindowBorder = WindowBorder.Resizable;
} }
switch (value) using (new XLock(window.Display))
{ {
case OpenTK.WindowState.Normal: switch (value)
Functions.XRaiseWindow(window.Display, window.WindowHandle); {
case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.WindowHandle);
break; break;
case OpenTK.WindowState.Maximized: case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_maximized_horizontal, _atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical); _atom_net_wm_state_maximized_vertical);
Functions.XRaiseWindow(window.Display, window.WindowHandle); Functions.XRaiseWindow(window.Display, window.WindowHandle);
break; break;
case OpenTK.WindowState.Minimized: case OpenTK.WindowState.Minimized:
// Todo: multiscreen support // Todo: multiscreen support
Functions.XIconifyWindow(window.Display, window.WindowHandle, window.Screen); Functions.XIconifyWindow(window.Display, window.WindowHandle, window.Screen);
break; break;
case OpenTK.WindowState.Fullscreen: case OpenTK.WindowState.Fullscreen:
//_previous_window_border = this.WindowBorder; //_previous_window_border = this.WindowBorder;
//this.WindowBorder = WindowBorder.Hidden; //this.WindowBorder = WindowBorder.Hidden;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_fullscreen, IntPtr.Zero); _atom_net_wm_state_fullscreen, IntPtr.Zero);
Functions.XRaiseWindow(window.Display, window.WindowHandle); Functions.XRaiseWindow(window.Display, window.WindowHandle);
break; break;
}
} }
if (temporary_resizable) if (temporary_resizable)