Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up IWindow and remove platform-agnostic code probing ISDLWindow #6438

Merged
merged 7 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading