[X11] Fixed WindowBorder and WindowState setters

After many hours of fighting with xlib, the monster is slain and
WindowBorder/WindowState changes now take effect without messing
up the window size or position on the desktop.

Phew!
This commit is contained in:
thefiddler 2014-05-09 13:10:23 +02:00
parent ab29797079
commit f0d0f6e53a

View file

@ -111,6 +111,13 @@ namespace OpenTK.Platform.X11
bool _decorations_hidden = false; bool _decorations_hidden = false;
// Store previous border and bounds
// when switching from WindowState.Normal
// to a different state. When switching
// back, reset window to these.s
WindowBorder _previous_window_border;
Size _previous_window_size;
MouseCursor cursor = MouseCursor.Default; MouseCursor cursor = MouseCursor.Default;
IntPtr cursorHandle; IntPtr cursorHandle;
bool cursor_visible = true; bool cursor_visible = true;
@ -1248,75 +1255,105 @@ namespace OpenTK.Platform.X11
{ {
OpenTK.WindowState current_state = this.WindowState; OpenTK.WindowState current_state = this.WindowState;
// When switching away from normal state, store
// the "normal" border and size. These will be used
// for restoring to normal state.
if (current_state == OpenTK.WindowState.Normal)
{
_previous_window_border = WindowBorder;
_previous_window_size = ClientSize;
}
if (current_state == value) if (current_state == value)
return; return;
Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.Handle.ToString(), Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.Handle.ToString(),
current_state.ToString(), value.ToString()); current_state.ToString(), value.ToString());
using (new XLock(window.Display)) // When minimizing the window, call XIconifyWindow and bail out.
// For other states, we first need to restore the window, set the
// new state and reset the window border and bounds.
if (value != OpenTK.WindowState.Minimized)
{ {
// Reset the current window state // Some WMs cannot switch between specific states directly,
if (current_state == OpenTK.WindowState.Minimized) // Switch back to a regular window first.
Functions.XMapWindow(window.Display, window.Handle); if (WindowBorder == WindowBorder.Fixed)
else if (current_state == OpenTK.WindowState.Fullscreen) {
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove, ChangeWindowBorder(WindowBorder.Resizable);
_atom_net_wm_state_fullscreen, }
IntPtr.Zero);
else if (current_state == OpenTK.WindowState.Maximized) ResetWindowState(current_state);
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle, }
_atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical); // Change to the desired WindowState.
// Note that OnWindowStateChanged is called inside
Functions.XSync(window.Display, false); // ProcessEvents.
} ChangeWindowState(value);
// We can't resize the window if its border is fixed, so make it resizable first. ProcessEvents();
bool temporary_resizable = false; }
WindowBorder previous_state = WindowBorder; }
if (WindowBorder != WindowBorder.Resizable)
{ void ResetWindowState(OpenTK.WindowState current_state)
temporary_resizable = true; {
WindowBorder = WindowBorder.Resizable; if (current_state != OpenTK.WindowState.Normal)
} {
using (new XLock(window.Display))
using (new XLock(window.Display)) {
{ switch (current_state)
switch (value)
{ {
case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.Handle);
break;
case OpenTK.WindowState.Maximized:
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.Handle);
break;
case OpenTK.WindowState.Minimized: case OpenTK.WindowState.Minimized:
// Todo: multiscreen support Functions.XMapWindow(window.Display, window.Handle);
Functions.XIconifyWindow(window.Display, window.Handle, window.Screen);
break; break;
case OpenTK.WindowState.Fullscreen: case OpenTK.WindowState.Fullscreen:
//_previous_window_border = this.WindowBorder; Functions.SendNetWMMessage(window,
//this.WindowBorder = WindowBorder.Hidden; _atom_net_wm_state,
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, _atom_remove,
_atom_net_wm_state_fullscreen, IntPtr.Zero); _atom_net_wm_state_fullscreen,
Functions.XRaiseWindow(window.Display, window.Handle); IntPtr.Zero);
break;
case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_toggle,
_atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical);
break; break;
} }
} }
}
}
if (temporary_resizable) void ChangeWindowState(OpenTK.WindowState value)
WindowBorder = previous_state; {
using (new XLock(window.Display))
{
switch (value)
{
case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.Handle);
ChangeWindowBorder(_previous_window_border,
_previous_window_size.Width, _previous_window_size.Height);
break;
ProcessEvents(); case OpenTK.WindowState.Maximized:
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.Handle);
break;
case OpenTK.WindowState.Minimized:
Functions.XIconifyWindow(window.Display, window.Handle, window.Screen);
break;
case OpenTK.WindowState.Fullscreen:
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_fullscreen, IntPtr.Zero);
Functions.XRaiseWindow(window.Display, window.Handle);
break;
}
} }
} }
@ -1328,47 +1365,67 @@ namespace OpenTK.Platform.X11
{ {
get get
{ {
if (IsWindowBorderHidden) if (IsWindowBorderHidden || WindowState == OpenTK.WindowState.Fullscreen)
return WindowBorder.Hidden; return WindowBorder.Hidden;
else if (!IsWindowBorderResizable)
if (IsWindowBorderResizable)
return WindowBorder.Resizable;
else
return WindowBorder.Fixed; return WindowBorder.Fixed;
else if (WindowState == OpenTK.WindowState.Maximized)
return _previous_window_border;
else
return WindowBorder.Resizable;
} }
set set
{ {
if (WindowBorder == value) if (WindowBorder == value)
return; return;
if (WindowBorder == WindowBorder.Hidden) // We cannot change the border of a fullscreen window.
EnableWindowDecorations(); // Record the new value and set it on the next WindowState
// change.
switch (value) if (WindowState == OpenTK.WindowState.Fullscreen)
{ {
case WindowBorder.Fixed: _previous_window_border = value;
Debug.Print("Making WindowBorder fixed."); return;
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();
break;
} }
ChangeWindowBorder(value);
OnWindowBorderChanged(EventArgs.Empty); OnWindowBorderChanged(EventArgs.Empty);
} }
} }
void ChangeWindowBorder(WindowBorder value)
{
ChangeWindowBorder(value, Width, Height);
}
void ChangeWindowBorder(WindowBorder value, int width, int height)
{
if (WindowBorder == WindowBorder.Hidden)
EnableWindowDecorations();
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.");
// Make the hidden border resizable, otherwise
// we won't be able to maximize the window or
// enter fullscreen mode.
SetWindowMinMax(_min_width, _min_height, -1, -1);
DisableWindowDecorations();
break;
}
ProcessEvents();
}
#endregion #endregion
#region Cursor #region Cursor