1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-15 04:12:57 +08:00

Merge pull request #18422 from smoogipoo/detect-exclusive-fullscreen

Detect exclusive fullscreen on Windows
This commit is contained in:
Dean Herbert 2022-06-02 15:13:02 +09:00 committed by GitHub
commit 5adbf85654
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 127 additions and 53 deletions

View File

@ -6,6 +6,7 @@ using NUnit.Framework;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
@ -83,7 +84,7 @@ namespace osu.Game.Tests.Visual.Settings
AddStep("clear label", () => textBox.LabelText = default); AddStep("clear label", () => textBox.LabelText = default);
AddAssert("default value button centre aligned to control size", () => Precision.AlmostEquals(restoreDefaultValueButton.Parent.DrawHeight, control.DrawHeight, 1)); AddAssert("default value button centre aligned to control size", () => Precision.AlmostEquals(restoreDefaultValueButton.Parent.DrawHeight, control.DrawHeight, 1));
AddStep("set warning text", () => textBox.WarningText = "This is some very important warning text! Hopefully it doesn't break the alignment of the default value indicator..."); AddStep("set warning text", () => textBox.SetNoticeText("This is some very important warning text! Hopefully it doesn't break the alignment of the default value indicator...", true));
AddAssert("default value button centre aligned to control size", () => Precision.AlmostEquals(restoreDefaultValueButton.Parent.DrawHeight, control.DrawHeight, 1)); AddAssert("default value button centre aligned to control size", () => Precision.AlmostEquals(restoreDefaultValueButton.Parent.DrawHeight, control.DrawHeight, 1));
} }
@ -129,16 +130,18 @@ namespace osu.Game.Tests.Visual.Settings
SettingsNumberBox numberBox = null; SettingsNumberBox numberBox = null;
AddStep("create settings item", () => Child = numberBox = new SettingsNumberBox()); AddStep("create settings item", () => Child = numberBox = new SettingsNumberBox());
AddAssert("warning text not created", () => !numberBox.ChildrenOfType<SettingsNoticeText>().Any()); AddAssert("warning text not created", () => !numberBox.ChildrenOfType<LinkFlowContainer>().Any());
AddStep("set warning text", () => numberBox.WarningText = "this is a warning!"); AddStep("set warning text", () => numberBox.SetNoticeText("this is a warning!", true));
AddAssert("warning text created", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 1); AddAssert("warning text created", () => numberBox.ChildrenOfType<LinkFlowContainer>().Single().Alpha == 1);
AddStep("unset warning text", () => numberBox.WarningText = default); AddStep("unset warning text", () => numberBox.ClearNoticeText());
AddAssert("warning text hidden", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 0); AddAssert("warning text hidden", () => !numberBox.ChildrenOfType<LinkFlowContainer>().Any());
AddStep("set warning text again", () => numberBox.WarningText = "another warning!"); AddStep("set warning text again", () => numberBox.SetNoticeText("another warning!", true));
AddAssert("warning text shown again", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 1); AddAssert("warning text shown again", () => numberBox.ChildrenOfType<LinkFlowContainer>().Single().Alpha == 1);
AddStep("set non warning text", () => numberBox.SetNoticeText("you did good!"));
} }
} }
} }

View File

@ -0,0 +1,29 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Localisation;
namespace osu.Game.Localisation
{
public static class LayoutSettingsStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.LayoutSettings";
/// <summary>
/// "Checking for fullscreen capabilities..."
/// </summary>
public static LocalisableString CheckingForFullscreenCapabilities => new TranslatableString(getKey(@"checking_for_fullscreen_capabilities"), @"Checking for fullscreen capabilities...");
/// <summary>
/// "osu! is running exclusive fullscreen, guaranteeing low latency!"
/// </summary>
public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running exclusive fullscreen, guaranteeing low latency!");
/// <summary>
/// "Unable to run exclusive fullscreen. You&#39;ll still experience some input latency."
/// </summary>
public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run exclusive fullscreen. You'll still experience some input latency.");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Platform.Windows;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
@ -34,10 +35,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
private Bindable<Size> sizeFullscreen; private Bindable<Size> sizeFullscreen;
private readonly BindableList<Size> resolutions = new BindableList<Size>(new[] { new Size(9999, 9999) }); private readonly BindableList<Size> resolutions = new BindableList<Size>(new[] { new Size(9999, 9999) });
private readonly IBindable<FullscreenCapability> fullscreenCapability = new Bindable<FullscreenCapability>(FullscreenCapability.Capable);
[Resolved] [Resolved]
private OsuGameBase game { get; set; } private OsuGameBase game { get; set; }
[Resolved]
private GameHost host { get; set; }
private SettingsDropdown<Size> resolutionDropdown; private SettingsDropdown<Size> resolutionDropdown;
private SettingsDropdown<Display> displayDropdown; private SettingsDropdown<Display> displayDropdown;
private SettingsDropdown<WindowMode> windowModeDropdown; private SettingsDropdown<WindowMode> windowModeDropdown;
@ -65,6 +70,9 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
windowModes.BindTo(host.Window.SupportedWindowModes); windowModes.BindTo(host.Window.SupportedWindowModes);
} }
if (host.Window is WindowsWindow windowsWindow)
fullscreenCapability.BindTo(windowsWindow.FullscreenCapability);
Children = new Drawable[] Children = new Drawable[]
{ {
windowModeDropdown = new SettingsDropdown<WindowMode> windowModeDropdown = new SettingsDropdown<WindowMode>
@ -139,6 +147,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
} }
}, },
}; };
fullscreenCapability.BindValueChanged(_ => Schedule(updateScreenModeWarning), true);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -150,8 +160,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
windowModeDropdown.Current.BindValueChanged(mode => windowModeDropdown.Current.BindValueChanged(mode =>
{ {
updateDisplayModeDropdowns(); updateDisplayModeDropdowns();
updateScreenModeWarning();
windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : default;
}, true); }, true);
windowModes.BindCollectionChanged((sender, args) => windowModes.BindCollectionChanged((sender, args) =>
@ -213,6 +222,38 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
} }
} }
private void updateScreenModeWarning()
{
if (windowModeDropdown.Current.Value != WindowMode.Fullscreen)
{
windowModeDropdown.SetNoticeText(GraphicsSettingsStrings.NotFullscreenNote, true);
return;
}
if (host.Window is WindowsWindow)
{
switch (fullscreenCapability.Value)
{
case FullscreenCapability.Unknown:
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.CheckingForFullscreenCapabilities, true);
break;
case FullscreenCapability.Capable:
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.OsuIsRunningExclusiveFullscreen);
break;
case FullscreenCapability.Incapable:
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.UnableToRunExclusiveFullscreen, true);
break;
}
}
else
{
// We can only detect exclusive fullscreen status on windows currently.
windowModeDropdown.ClearNoticeText();
}
}
private void bindPreviewEvent(Bindable<float> bindable) private void bindPreviewEvent(Bindable<float> bindable)
{ {
bindable.ValueChanged += _ => bindable.ValueChanged += _ =>

View File

@ -48,7 +48,16 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
frameLimiterDropdown.Current.BindValueChanged(limit => frameLimiterDropdown.Current.BindValueChanged(limit =>
{ {
frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : default; switch (limit.NewValue)
{
case FrameSync.Unlimited:
frameLimiterDropdown.SetNoticeText(GraphicsSettingsStrings.UnlimitedFramesNote, true);
break;
default:
frameLimiterDropdown.ClearNoticeText();
break;
}
}, true); }, true);
} }
} }

View File

@ -117,9 +117,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input
if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
{ {
if (highPrecision.NewValue) if (highPrecision.NewValue)
highPrecisionMouse.WarningText = MouseSettingsStrings.HighPrecisionPlatformWarning; highPrecisionMouse.SetNoticeText(MouseSettingsStrings.HighPrecisionPlatformWarning, true);
else else
highPrecisionMouse.WarningText = null; highPrecisionMouse.ClearNoticeText();
} }
}, true); }, true);
} }

View File

@ -11,6 +11,7 @@ using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK; using osuTK;
using osu.Game.Localisation; using osu.Game.Localisation;
@ -95,11 +96,13 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Text = TabletSettingsStrings.NoTabletDetected, Text = TabletSettingsStrings.NoTabletDetected,
}, },
new SettingsNoticeText(colours) new LinkFlowContainer(cp => cp.Colour = colours.Yellow)
{ {
TextAnchor = Anchor.TopCentre, TextAnchor = Anchor.TopCentre,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
}.With(t => }.With(t =>
{ {
if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux)

View File

@ -61,7 +61,10 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface
user.BindValueChanged(u => user.BindValueChanged(u =>
{ {
backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : default; if (u.NewValue?.IsSupporter != true)
backgroundSourceDropdown.SetNoticeText(UserInterfaceStrings.NotSupporterNote, true);
else
backgroundSourceDropdown.ClearNoticeText();
}, true); }, true);
} }
} }

View File

@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings
private SpriteText labelText; private SpriteText labelText;
private OsuTextFlowContainer warningText; private OsuTextFlowContainer noticeText;
public bool ShowsDefaultIndicator = true; public bool ShowsDefaultIndicator = true;
private readonly Container defaultValueIndicatorContainer; private readonly Container defaultValueIndicatorContainer;
@ -70,27 +70,32 @@ namespace osu.Game.Overlays.Settings
} }
/// <summary> /// <summary>
/// Text to be displayed at the bottom of this <see cref="SettingsItem{T}"/>. /// Clear any warning text.
/// Generally used to recommend the user change their setting as the current one is considered sub-optimal.
/// </summary> /// </summary>
public LocalisableString? WarningText public void ClearNoticeText()
{ {
set noticeText?.Expire();
noticeText = null;
}
/// <summary>
/// Set the text to be displayed at the bottom of this <see cref="SettingsItem{T}"/>.
/// Generally used to provide feedback to a user about a sub-optimal setting.
/// </summary>
/// <param name="text">The text to display.</param>
/// <param name="isWarning">Whether the text is in a warning state. Will decide how this is visually represented.</param>
public void SetNoticeText(LocalisableString text, bool isWarning = false)
{
ClearNoticeText();
// construct lazily for cases where the label is not needed (may be provided by the Control).
FlowContent.Add(noticeText = new LinkFlowContainer(cp => cp.Colour = isWarning ? colours.Yellow : colours.Green)
{ {
bool hasValue = value != default; RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
if (warningText == null) Margin = new MarginPadding { Bottom = 5 },
{ Text = text,
if (!hasValue) });
return;
// construct lazily for cases where the label is not needed (may be provided by the Control).
FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } });
}
warningText.Alpha = hasValue ? 1 : 0;
warningText.Text = value ?? default;
}
} }
public virtual Bindable<T> Current public virtual Bindable<T> Current

View File

@ -1,19 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Settings
{
public class SettingsNoticeText : LinkFlowContainer
{
public SettingsNoticeText(OsuColour colours)
: base(s => s.Colour = colours.Yellow)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
}
}