Skip to content

Commit

Permalink
Merge pull request #6438 from Susko3/clean-up-IWindow
Browse files Browse the repository at this point in the history
Clean up `IWindow` and remove platform-agnostic code probing `ISDLWindow`
  • Loading branch information
frenzibyte authored Nov 29, 2024
2 parents 0c99586 + e8adb6e commit 902be06
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 52 deletions.
4 changes: 2 additions & 2 deletions osu.Framework.Tests/Visual/Platform/TestSceneBorderless.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public partial class TestSceneBorderless : FrameworkTestScene
private readonly SpriteText currentWindowMode = new SpriteText();
private readonly SpriteText currentDisplay = new SpriteText();

private ISDLWindow? window;
private IWindow? window;
private readonly Bindable<WindowMode> windowMode = new Bindable<WindowMode>();

public TestSceneBorderless()
Expand Down Expand Up @@ -57,7 +57,7 @@ public TestSceneBorderless()
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager config, GameHost host)
{
window = host.Window as ISDLWindow;
window = host.Window;
config.BindWith(FrameworkSetting.WindowMode, windowMode);

windowMode.BindValueChanged(mode => currentWindowMode.Text = $"Window Mode: {mode.NewValue}", true);
Expand Down
2 changes: 1 addition & 1 deletion osu.Framework.Tests/Visual/Platform/TestSceneFullscreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void TestScreenModeSwitch()
if (window.SupportedWindowModes.Contains(WindowMode.Fullscreen))
{
AddStep("change to fullscreen", () => windowMode.Value = WindowMode.Fullscreen);
AddAssert("window position updated", () => ((ISDLWindow)window).Position, () => Is.EqualTo(window.CurrentDisplayBindable.Value.Bounds.Location));
AddAssert("window position updated", () => window.Position, () => Is.EqualTo(window.CurrentDisplayBindable.Value.Bounds.Location));
testResolution(1920, 1080);
testResolution(1280, 960);
testResolution(9999, 9999);
Expand Down
28 changes: 14 additions & 14 deletions osu.Framework.Tests/Visual/Platform/TestSceneWindowed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ public partial class TestSceneWindowed : FrameworkTestScene
[Resolved]
private FrameworkConfigManager config { get; set; }

private ISDLWindow sdlWindow;
private IWindow window;

[BackgroundDependencyLoader]
private void load()
{
sdlWindow = (ISDLWindow)host.Window;
window = host.Window;
Children = new Drawable[]
{
new FillFlowContainer
Expand Down Expand Up @@ -64,12 +64,12 @@ private void load()
}

[SetUp]
public void SetUp() => Schedule(() => sdlWindow.Resizable = true);
public void SetUp() => Schedule(() => window.Resizable = true);

[Test]
public void TestToggleResizable()
{
AddToggleStep("toggle resizable", state => sdlWindow.Resizable = state);
AddToggleStep("toggle resizable", state => window.Resizable = state);
}

[Test]
Expand All @@ -79,16 +79,16 @@ public void TestMinimumSize()
const int min_height = 768;

AddStep("reset window to valid size", () => setWindowSize(new Size(640, 480)));
AddStep("set minimum size above client size", () => sdlWindow.MinSize = new Size(min_width, min_height));
AddStep("set minimum size above client size", () => window.MinSize = new Size(min_width, min_height));
assertWindowSize(new Size(min_width, min_height));

AddStep("reset window to valid size", () => setWindowSize(new Size(1280, 960)));
AddStep("set client size below minimum size", () => setWindowSize(new Size(640, 480)));
assertWindowSize(new Size(min_width, min_height));

AddStep("overlapping size throws", () => Assert.Throws<InvalidOperationException>(() => sdlWindow.MinSize = sdlWindow.MaxSize + new Size(1, 1)));
AddStep("negative size throws", () => Assert.Throws<InvalidOperationException>(() => sdlWindow.MinSize = new Size(-1, -1)));
AddStep("reset minimum size", () => sdlWindow.MinSize = new Size(640, 480));
AddStep("overlapping size throws", () => Assert.Throws<InvalidOperationException>(() => window.MinSize = window.MaxSize + new Size(1, 1)));
AddStep("negative size throws", () => Assert.Throws<InvalidOperationException>(() => window.MinSize = new Size(-1, -1)));
AddStep("reset minimum size", () => window.MinSize = new Size(640, 480));
}

[Test]
Expand All @@ -98,27 +98,27 @@ public void TestMaximumSize()
const int max_height = 768;

AddStep("reset window to valid size", () => setWindowSize(new Size(1280, 960)));
AddStep("set maximum size below client size", () => sdlWindow.MaxSize = new Size(max_width, max_height));
AddStep("set maximum size below client size", () => window.MaxSize = new Size(max_width, max_height));
assertWindowSize(new Size(max_width, max_height));

// when the maximum window size changes to a value below the current size, the window implicitly enters maximised state.
// when in maximised state, the "windowed size" config bindable is ineffective until the window goes back to normal.
AddStep("reset window to normal state", () => sdlWindow.WindowState = WindowState.Normal);
AddStep("reset window to normal state", () => window.WindowState = WindowState.Normal);

AddStep("reset window to valid size", () => setWindowSize(new Size(640, 480)));
AddStep("set client size above maximum size", () => setWindowSize(new Size(1280, 960)));
assertWindowSize(new Size(max_width, max_height));

AddStep("overlapping size throws", () => Assert.Throws<InvalidOperationException>(() => sdlWindow.MaxSize = sdlWindow.MinSize - new Size(1, 1)));
AddStep("negative size throws", () => Assert.Throws<InvalidOperationException>(() => sdlWindow.MaxSize = new Size(-1, -1)));
AddStep("reset maximum size", () => sdlWindow.MaxSize = new Size(65536, 65536));
AddStep("overlapping size throws", () => Assert.Throws<InvalidOperationException>(() => window.MaxSize = window.MinSize - new Size(1, 1)));
AddStep("negative size throws", () => Assert.Throws<InvalidOperationException>(() => window.MaxSize = new Size(-1, -1)));
AddStep("reset maximum size", () => window.MaxSize = new Size(65536, 65536));
}

private void setWindowSize(Size size) => config.SetValue(FrameworkSetting.WindowedSize, size);

private void assertWindowSize(Size size)
{
AddAssert($"client size = {size.Width}x{size.Height} (with scale)", () => sdlWindow.ClientSize == (size * sdlWindow.Scale).ToSize());
AddAssert($"client size = {size.Width}x{size.Height} (with scale)", () => window.ClientSize == (size * window.Scale).ToSize());
AddAssert($"size in config = {size.Width}x{size.Height}", () => config.Get<Size>(FrameworkSetting.WindowedSize) == size);
}
}
Expand Down
4 changes: 2 additions & 2 deletions osu.Framework.Tests/Visual/Platform/WindowDisplaysPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public partial class WindowDisplaysPreview : Container
private static readonly Color4 window_fill = new Color4(95, 113, 197, 255);
private static readonly Color4 window_stroke = new Color4(36, 59, 166, 255);

private ISDLWindow? window;
private IWindow? window;
private readonly Bindable<WindowMode> windowMode = new Bindable<WindowMode>();
private readonly Bindable<Display> currentDisplay = new Bindable<Display>();

Expand Down Expand Up @@ -90,7 +90,7 @@ public WindowDisplaysPreview()
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager config, GameHost host)
{
window = host.Window as ISDLWindow;
window = host.Window;
config.BindWith(FrameworkSetting.WindowMode, windowMode);

if (window != null)
Expand Down
4 changes: 2 additions & 2 deletions osu.Framework/Input/UserInputManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ private bool mouseOutsideAllDisplays(Vector2 mousePosition)
switch (Host.Window.WindowMode.Value)
{
case WindowMode.Windowed:
windowLocation = Host.Window is ISDLWindow sdlWindow ? sdlWindow.Position : Point.Empty;
windowLocation = Host.Window.Position;
break;

default:
windowLocation = Host.Window.CurrentDisplayBindable.Value.Bounds.Location;
break;
}

float scale = Host.Window is ISDLWindow window ? window.Scale : 1;
float scale = Host.Window.Scale;
mousePosition /= scale;

int x = (int)MathF.Floor(windowLocation.X + mousePosition.X);
Expand Down
7 changes: 0 additions & 7 deletions osu.Framework/Platform/ISDLWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Drawing;
using osu.Framework.Bindables;
using osu.Framework.Input;
using osuTK;
Expand All @@ -27,15 +26,9 @@ internal interface ISDLWindow : IWindow
event Action<Key> KeyUp;
event Action<string> TextInput;
event TextEditingDelegate TextEditing;
event Action<WindowState> WindowStateChanged;

Bindable<CursorState> CursorStateBindable { get; }

Point Position { get; }
Size Size { get; }
float Scale { get; }
bool Resizable { get; set; }

bool MouseAutoCapture { set; }
bool RelativeMouseMode { get; set; }
bool CapsLockPressed { get; }
Expand Down
66 changes: 47 additions & 19 deletions osu.Framework/Platform/IWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ public interface IWindow : IDisposable
/// </summary>
void Create();

/// <summary>
/// Start the window's run loop.
/// Is a blocking call on desktop platforms, and a non-blocking call on mobile platforms.
/// </summary>
void Run();

/// <summary>
/// Invoked once a draw session has finished.
/// </summary>
void OnDraw();

/// <summary>
/// Forcefully closes the window.
/// </summary>
void Close();

/// <summary>
/// Invoked once every window event loop.
/// </summary>
Expand Down Expand Up @@ -81,7 +97,7 @@ public interface IWindow : IDisposable
/// <summary>
/// Invoked when the user drops a file into the window.
/// </summary>
public event Action<string>? DragDrop;
event Action<string>? DragDrop;

/// <summary>
/// Whether the OS cursor is currently contained within the game window.
Expand All @@ -108,6 +124,11 @@ public interface IWindow : IDisposable
/// </summary>
WindowState WindowState { get; set; }

/// <summary>
/// Invoked when <see cref="WindowState"/> changes.
/// </summary>
event Action<WindowState>? WindowStateChanged;

/// <summary>
/// Returns the default <see cref="WindowMode"/> for the implementation.
/// </summary>
Expand Down Expand Up @@ -161,11 +182,6 @@ public interface IWindow : IDisposable
/// </summary>
IBindable<DisplayMode> CurrentDisplayMode { get; }

/// <summary>
/// Forcefully closes the window.
/// </summary>
void Close();

/// <summary>
/// Attempts to raise the window, bringing it above other windows and requesting input focus.
/// </summary>
Expand Down Expand Up @@ -211,44 +227,51 @@ public interface IWindow : IDisposable
/// </summary>
void DisableScreenSuspension();

/// <summary>
/// Start the window's run loop.
/// Is a blocking call on desktop platforms, and a non-blocking call on mobile platforms.
/// </summary>
void Run();

/// <summary>
/// Invoked once a draw session has finished.
/// </summary>
void OnDraw();

/// <summary>
/// Whether the window currently has focus.
/// </summary>
[Obsolete("Use IWindow.IsActive.Value instead.")] // can be removed 20250528
bool Focused { get; }

/// <summary>
/// Sets the window icon to the provided <paramref name="imageStream"/>.
/// </summary>
public void SetIconFromStream(Stream imageStream);
void SetIconFromStream(Stream imageStream);

/// <summary>
/// Convert a screen based coordinate to local window space.
/// </summary>
/// <param name="point"></param>
[Obsolete("This member should not be used. It was never properly implemented for cross-platform use.")] // can be removed 20250528
Point PointToClient(Point point);

/// <summary>
/// Convert a window based coordinate to global screen space.
/// </summary>
/// <param name="point"></param>
[Obsolete("This member should not be used. It was never properly implemented for cross-platform use.")] // can be removed 20250528
Point PointToScreen(Point point);

/// <summary>
/// The client size of the window (excluding any window decoration/border).
/// The client size of the window in pixels (excluding any window decoration/border).
/// </summary>
Size ClientSize { get; }

/// <summary>
/// The position of the window.
/// </summary>
Point Position { get; }

/// <summary>
/// The size of the window in scaled pixels (excluding any window decoration/border).
/// </summary>
Size Size { get; }

/// <summary>
/// The ratio of <see cref="ClientSize"/> and <see cref="Size"/>.
/// </summary>
float Scale { get; }

/// <summary>
/// The minimum size of the window.
/// </summary>
Expand All @@ -261,6 +284,11 @@ public interface IWindow : IDisposable
/// <exception cref="InvalidOperationException">Thrown when setting a negative or zero size, or a size less than <see cref="MinSize"/>.</exception>
Size MaxSize { get; set; }

/// <summary>
/// Gets or sets whether the window is user-resizable.
/// </summary>
bool Resizable { get; set; }

/// <summary>
/// The window title.
/// </summary>
Expand Down
8 changes: 3 additions & 5 deletions osu.Framework/Platform/Windows/WindowsGLRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ protected override void Initialise(IGraphicsSurface graphicsSurface)
{
base.Initialise(graphicsSurface);

ISDLWindow windowsWindow = (ISDLWindow)host.Window;

bool isIntel = GL.GetString(StringName.Vendor).Trim() == "Intel";

if (isIntel)
Expand All @@ -40,9 +38,9 @@ protected override void Initialise(IGraphicsSurface graphicsSurface)
else
{
// For all other vendors, support depends on the system setup - e.g. NVIDIA Optimus doesn't support exclusive fullscreen with OpenGL.
windowsWindow.IsActive.BindValueChanged(_ => detectFullscreenCapability(windowsWindow));
windowsWindow.WindowStateChanged += _ => detectFullscreenCapability(windowsWindow);
detectFullscreenCapability(windowsWindow);
host.Window.IsActive.BindValueChanged(_ => detectFullscreenCapability(host.Window));
host.Window.WindowStateChanged += _ => detectFullscreenCapability(host.Window);
detectFullscreenCapability(host.Window);
}
}

Expand Down

0 comments on commit 902be06

Please sign in to comment.