[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,44 +1255,86 @@ 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());
// 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)
{
// Some WMs cannot switch between specific states directly,
// Switch back to a regular window first.
if (WindowBorder == WindowBorder.Fixed)
{
ChangeWindowBorder(WindowBorder.Resizable);
}
ResetWindowState(current_state);
}
// Change to the desired WindowState.
// Note that OnWindowStateChanged is called inside
// ProcessEvents.
ChangeWindowState(value);
ProcessEvents();
}
}
void ResetWindowState(OpenTK.WindowState current_state)
{
if (current_state != OpenTK.WindowState.Normal)
{
using (new XLock(window.Display)) using (new XLock(window.Display))
{ {
// Reset the current window state switch (current_state)
if (current_state == OpenTK.WindowState.Minimized) {
case OpenTK.WindowState.Minimized:
Functions.XMapWindow(window.Display, window.Handle); Functions.XMapWindow(window.Display, window.Handle);
else if (current_state == OpenTK.WindowState.Fullscreen) break;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove,
case OpenTK.WindowState.Fullscreen:
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_remove,
_atom_net_wm_state_fullscreen, _atom_net_wm_state_fullscreen,
IntPtr.Zero); IntPtr.Zero);
else if (current_state == OpenTK.WindowState.Maximized) break;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle,
case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_toggle,
_atom_net_wm_state_maximized_horizontal, _atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical); _atom_net_wm_state_maximized_vertical);
break;
Functions.XSync(window.Display, false);
} }
// We can't resize the window if its border is fixed, so make it resizable first. }
bool temporary_resizable = false; }
WindowBorder previous_state = WindowBorder; }
if (WindowBorder != WindowBorder.Resizable)
void ChangeWindowState(OpenTK.WindowState value)
{ {
temporary_resizable = true;
WindowBorder = WindowBorder.Resizable;
}
using (new XLock(window.Display)) using (new XLock(window.Display))
{ {
switch (value) switch (value)
{ {
case OpenTK.WindowState.Normal: case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.Handle); Functions.XRaiseWindow(window.Display, window.Handle);
ChangeWindowBorder(_previous_window_border,
_previous_window_size.Width, _previous_window_size.Height);
break; break;
case OpenTK.WindowState.Maximized: case OpenTK.WindowState.Maximized:
@ -1293,31 +1342,19 @@ namespace OpenTK.Platform.X11
_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.Handle); Functions.XRaiseWindow(window.Display, window.Handle);
break; break;
case OpenTK.WindowState.Minimized: case OpenTK.WindowState.Minimized:
// Todo: multiscreen support
Functions.XIconifyWindow(window.Display, window.Handle, window.Screen); Functions.XIconifyWindow(window.Display, window.Handle, window.Screen);
break; break;
case OpenTK.WindowState.Fullscreen: case OpenTK.WindowState.Fullscreen:
//_previous_window_border = this.WindowBorder;
//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.Handle); Functions.XRaiseWindow(window.Display, window.Handle);
break; break;
} }
} }
if (temporary_resizable)
WindowBorder = previous_state;
ProcessEvents();
}
} }
#endregion #endregion
@ -1328,19 +1365,41 @@ 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;
// We cannot change the border of a fullscreen window.
// Record the new value and set it on the next WindowState
// change.
if (WindowState == OpenTK.WindowState.Fullscreen)
{
_previous_window_border = value;
return;
}
ChangeWindowBorder(value);
OnWindowBorderChanged(EventArgs.Empty);
}
}
void ChangeWindowBorder(WindowBorder value)
{
ChangeWindowBorder(value, Width, Height);
}
void ChangeWindowBorder(WindowBorder value, int width, int height)
{
if (WindowBorder == WindowBorder.Hidden) if (WindowBorder == WindowBorder.Hidden)
EnableWindowDecorations(); EnableWindowDecorations();
@ -1348,25 +1407,23 @@ namespace OpenTK.Platform.X11
{ {
case WindowBorder.Fixed: case WindowBorder.Fixed:
Debug.Print("Making WindowBorder fixed."); Debug.Print("Making WindowBorder fixed.");
SetWindowMinMax((short)Width, (short)Height, (short)Width, (short)Height); SetWindowMinMax((short)width, (short)height, (short)width, (short)height);
break; break;
case WindowBorder.Resizable: case WindowBorder.Resizable:
Debug.Print("Making WindowBorder resizable."); Debug.Print("Making WindowBorder resizable.");
SetWindowMinMax(_min_width, _min_height, -1, -1); SetWindowMinMax(_min_width, _min_height, -1, -1);
break; break;
case WindowBorder.Hidden: case WindowBorder.Hidden:
Debug.Print("Making 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(); DisableWindowDecorations();
break; break;
} }
OnWindowBorderChanged(EventArgs.Empty); ProcessEvents();
}
} }
#endregion #endregion