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

Bring back borderless mode for macOS and Linux #6264

Merged
merged 6 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 3 additions & 2 deletions osu.Framework/Platform/SDL/SDL3Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -859,16 +859,17 @@ public static SDL_Scancode ToScancode(this InputKey inputKey)
}
}

public static WindowState ToWindowState(this SDL_WindowFlags windowFlags)
public static WindowState ToWindowState(this SDL_WindowFlags windowFlags, bool isFullscreenBorderless)
{
// for windows
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_BORDERLESS))
return WindowState.FullscreenBorderless;

if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
return WindowState.Minimised;

if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN))
return WindowState.Fullscreen;
return isFullscreenBorderless ? WindowState.FullscreenBorderless : WindowState.Fullscreen;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding #6264 (comment), it appears that once the window is in borderless mode, it does not have the SDL_WINDOW_FULLSCREEN flag set:

CleanShot 2024-05-20 at 15 19 01

Therefore, the WindowState is kept at normal even after the window has switched to borderless, and sizeWindowed becomes corrupted as a result, causing the window to become maximised when returning from borderless.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@frenzibyte could you re-test this?

It's possible that this is because the window has not yet entered the fullscreen borderless mode due to animations still happening. Are the SDL window flags correct after the SDL_EVENT_WINDOW_ENTER_FULLSCREEN event arrives?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can reproduce again, and the statement above seems correct. The following path is triggered before the SDL_EVENT_WINDOW_ENTER_FULLSCREEN event, causing the size bindable to incorrectly store the borderless size:

case SDL_EventType.SDL_EVENT_WINDOW_RESIZED:
// polling via SDL_PollEvent blocks on resizes (https://stackoverflow.com/a/50858339)
if (!updatingWindowStateAndSize)
fetchWindowSize();
break;

I recall there was something about SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED being more reliable than SDL_EVENT_WINDOW_RESIZED to get the window size while the window is in its final state, I'm not sure how correct that is right now.

All I can confirm is that SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED gets called after SDL_EVENT_WINDOW_ENTER_FULLSCREEN, and we have only been handling SDL_EVENT_WINDOW_RESIZED so the game doesn't look weird when resizing it. Perhaps we can just not store the window size in the "resized" event.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following path is triggered [...]

When this is triggered, what is the value of SDL_GetWindowFlags(SDLWindowHandle)? Framework has cached a stale state, but what does SDL say?

Also please still check this:

Are the SDL window flags correct after the SDL_EVENT_WINDOW_ENTER_FULLSCREEN event arrives?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does have SDL_WINDOW_FULLSCREEN when checking the flags at SDL_EVENT_WINDOW_RESIZED, while WindowState is indeed stale.

The next event triggered after resize is SDL_EVENT_WINDOW_ENTER_FULLSCREEN, which is what updates the WindowState to FullscreenBorderless because of calling updateAndFetchWindowSpecifics() I suppose, and yes the SDL window flags remains correct thereafter.


if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MAXIMIZED))
return WindowState.Maximised;
Expand Down
18 changes: 12 additions & 6 deletions osu.Framework/Platform/SDL3Window_Windowing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,7 @@ public virtual IEnumerable<WindowMode> SupportedWindowModes
if (RuntimeInfo.IsMobile)
return new[] { Configuration.WindowMode.Fullscreen };

if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
return Enum.GetValues<WindowMode>();

return new[] { Configuration.WindowMode.Windowed, Configuration.WindowMode.Fullscreen };
return Enum.GetValues<WindowMode>();
}
}

Expand Down Expand Up @@ -577,7 +574,7 @@ private unsafe void updateAndFetchWindowSpecifics()
}
else
{
windowState = SDL3.SDL_GetWindowFlags(SDLWindowHandle).ToWindowState();
windowState = SDL3.SDL_GetWindowFlags(SDLWindowHandle).ToWindowState(SDL3.SDL_GetWindowFullscreenMode(SDLWindowHandle) == null);
}

if (windowState != stateBefore)
Expand Down Expand Up @@ -799,7 +796,16 @@ private void storeWindowSizeToConfig()
/// <returns>
/// The size of the borderless window's draw area.
/// </returns>
protected virtual Size SetBorderless(Display display) => throw new PlatformNotSupportedException();
protected virtual unsafe Size SetBorderless(Display display)
{
ensureWindowOnDisplay(display);

// this is a generally sane method of handling borderless, and works well on macOS and linux.
SDL3.SDL_SetWindowFullscreenMode(SDLWindowHandle, null);
SDL3.SDL_SetWindowFullscreen(SDLWindowHandle, SDL_bool.SDL_TRUE);

return display.Bounds.Size;
}

#endregion

Expand Down
Loading