Skip to content

Commit

Permalink
Merge pull request ppy#5459 from Susko3/fix-changing-displays
Browse files Browse the repository at this point in the history
Fix changing displays working only in windowed
  • Loading branch information
peppy authored Oct 21, 2022
2 parents 7a079c8 + e0cd44a commit ef5c6a8
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
81 changes: 81 additions & 0 deletions osu.Framework.Tests/Visual/Platform/TestSceneCurrentDisplay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Platform;

namespace osu.Framework.Tests.Visual.Platform
{
[Ignore("This test cannot be run in headless mode (a window instance is required).")]
public class TestSceneCurrentDisplay : FrameworkTestScene
{
private IWindow window = null!;

public TestSceneCurrentDisplay()
{
Children = new Drawable[]
{
new WindowDisplaysPreview
{
RelativeSizeAxes = Axes.Both
}
};
}

[BackgroundDependencyLoader]
private void load(GameHost host)
{
window = host.Window.AsNonNull();
}

[TestCase(WindowState.Normal)]
[TestCase(WindowState.Maximised)]
[TestCase(WindowState.Minimised)]
[TestCase(WindowState.FullscreenBorderless)]
[TestCase(WindowState.Fullscreen)]
public void TestChangeCurrentDisplay(WindowState startingState)
{
Display? display = null;

WindowMode startingMode = getWindowModeForState(startingState);

// this shouldn't be necessary, but SDL2DesktopWindow doesn't set the config WindowMode when changing the WindowState only.
AddStep($"switch to {startingMode}", () => window.WindowMode.Value = startingMode);

AddStep($"switch to {startingState}", () => window.WindowState = startingState);
AddStep("fetch a different display", () =>
{
int current = window.CurrentDisplayBindable.Value.Index;
display = window.Displays.First(d => d.Index != current);
});
AddStep("change to that display", () => window.CurrentDisplayBindable.Value = display);
AddAssert("display changed to requested", () => window.CurrentDisplayBindable.Value, () => Is.EqualTo(display));

for (int i = 0; i < 3; i++)
{
AddStep("cycle mode", () => window.CycleMode());
AddAssert("display hasn't changed", () => window.CurrentDisplayBindable.Value, () => Is.EqualTo(display));
}
}

private WindowMode getWindowModeForState(WindowState state)
{
switch (state)
{
default:
return WindowMode.Windowed;

case WindowState.Fullscreen:
return WindowMode.Fullscreen;

case WindowState.FullscreenBorderless:
return WindowMode.Borderless;
}
}
}
}
37 changes: 35 additions & 2 deletions osu.Framework/Platform/SDL2DesktopWindow_Windowing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ private void updateWindowStateAndSize(WindowState windowState, Display display,
// this is mentioned by multiple sources as an SDL issue, which seems to resolve by similar means (see https://discourse.libsdl.org/t/sdl-setwindowsize-does-not-work-in-fullscreen/20711/4).
SDL.SDL_SetWindowBordered(SDLWindowHandle, SDL.SDL_bool.SDL_TRUE);
SDL.SDL_SetWindowFullscreen(SDLWindowHandle, (uint)SDL.SDL_bool.SDL_FALSE);
SDL.SDL_RestoreWindow(SDLWindowHandle);

switch (windowState)
{
Expand All @@ -563,6 +564,8 @@ private void updateWindowStateAndSize(WindowState windowState, Display display,

Size = new Size(closestMode.w, closestMode.h);

ensureWindowOnDisplay(display);

SDL.SDL_SetWindowDisplayMode(SDLWindowHandle, ref closestMode);
SDL.SDL_SetWindowFullscreen(SDLWindowHandle, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);
break;
Expand All @@ -573,13 +576,17 @@ private void updateWindowStateAndSize(WindowState windowState, Display display,

case WindowState.Maximised:
SDL.SDL_RestoreWindow(SDLWindowHandle);

ensureWindowOnDisplay(display);

SDL.SDL_MaximizeWindow(SDLWindowHandle);

SDL.SDL_GL_GetDrawableSize(SDLWindowHandle, out int w, out int h);
Size = new Size(w, h);
break;

case WindowState.Minimised:
ensureWindowOnDisplay(display);
SDL.SDL_MinimizeWindow(SDLWindowHandle);
break;
}
Expand Down Expand Up @@ -633,10 +640,34 @@ private void readWindowPositionFromConfig(WindowState windowState, Display displ

var configPosition = new Vector2((float)windowPositionX.Value, (float)windowPositionY.Value);

moveWindowTo(display, configPosition);
}

/// <summary>
/// Ensures that the window is located on the provided <see cref="Display"/>.
/// </summary>
/// <param name="display">The <see cref="Display"/> to center the window on.</param>
private void ensureWindowOnDisplay(Display display)
{
if (display.Index == SDL.SDL_GetWindowDisplayIndex(SDLWindowHandle))
return;

moveWindowTo(display, new Vector2(0.5f));
}

/// <summary>
/// Moves the window to be centred around the normalised <paramref name="position"/> on a <paramref name="display"/>.
/// </summary>
/// <param name="display">The <see cref="Display"/> to move the window to.</param>
/// <param name="position">Relative position on the display, normalised to <c>[-0.5, 1.5]</c>.</param>
private void moveWindowTo(Display display, Vector2 position)
{
Debug.Assert(position == Vector2.Clamp(position, new Vector2(-0.5f), new Vector2(1.5f)));

var displayBounds = display.Bounds;
var windowSize = sizeWindowed.Value;
int windowX = (int)Math.Round((displayBounds.Width - windowSize.Width) * configPosition.X);
int windowY = (int)Math.Round((displayBounds.Height - windowSize.Height) * configPosition.Y);
int windowX = (int)Math.Round((displayBounds.Width - windowSize.Width) * position.X);
int windowY = (int)Math.Round((displayBounds.Height - windowSize.Height) * position.Y);

Position = new Point(windowX + displayBounds.X, windowY + displayBounds.Y);
}
Expand Down Expand Up @@ -681,6 +712,8 @@ private void storeWindowSizeToConfig()
/// </returns>
protected virtual Size SetBorderless(Display display)
{
ensureWindowOnDisplay(display);

// this is a generally sane method of handling borderless, and works well on macOS and linux.
SDL.SDL_SetWindowFullscreen(SDLWindowHandle, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);

Expand Down

0 comments on commit ef5c6a8

Please sign in to comment.