Skip to content

Commit

Permalink
Merge pull request #5970 from ItsShamed/flash-window
Browse files Browse the repository at this point in the history
Implement window flashing
  • Loading branch information
bdach authored Aug 21, 2023
2 parents 26b92b1 + ddd2b39 commit 9c5cf1d
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
73 changes: 73 additions & 0 deletions osu.Framework.Tests/Visual/Platform/TestSceneWindowFlash.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 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.Runtime.Versioning;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Platform;

namespace osu.Framework.Tests.Visual.Platform
{
[Ignore("This test cannot run in headless mode (a window instance is required).")]
[SupportedOSPlatform("windows")]
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public partial class TestSceneWindowFlash : FrameworkTestScene
{
private IBindable<bool> isActive = null!;
private IWindow? window;
private SpriteText text = null!;
private readonly Bindable<bool> flashUntilFocused = new BindableBool();

[BackgroundDependencyLoader]
private void load(GameHost gameHost)
{
isActive = gameHost.IsActive.GetBoundCopy();
window = gameHost.Window;
Child = new FillFlowContainer
{
Direction = FillDirection.Vertical,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
text = new SpriteText
{
Text = "This window will flash as soon as you un-focus it.",
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
}
};
}

protected override void LoadComplete()
{
base.LoadComplete();

flashUntilFocused.BindValueChanged(e =>
{
window?.CancelFlash();
text.Text = "This window will flash "
+ (e.NewValue ? "continuously, until focused again, " : "briefly")
+ " as soon as it is unfocused.";
}, true);

isActive.BindValueChanged(e =>
{
if (!e.NewValue)
window?.Flash(flashUntilFocused.Value);
}, true);
}

[Test]
public void TestBasic()
{
AddToggleStep("Flash until focused", a => flashUntilFocused.Value = a);
}
}
}
20 changes: 20 additions & 0 deletions osu.Framework/Platform/IWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,26 @@ public interface IWindow : IDisposable
/// </summary>
void Raise();

/// <summary>
/// Attempts to flash the window in order to request the user's attention.
/// </summary>
/// <remarks>
/// On platforms which don't support any kind of flashing (ie. mobile), this will be a no-op.
/// </remarks>
/// <param name="flashUntilFocused">
/// When <c>true</c>, the window will flash until it is focused again.
/// When <c>false</c> it will only flash momentarily.
/// </param>
void Flash(bool flashUntilFocused = false);

/// <summary>
/// Attempts to cancel any window flash requested with <see cref="Flash"/>.
/// </summary>
/// <remarks>
/// On platforms which don't support any kind of flashing (ie. mobile), this will be a no-op.
/// </remarks>
void CancelFlash();

/// <summary>
/// Start the window's run loop.
/// Is a blocking call on desktop platforms, and a non-blocking call on mobile platforms.
Expand Down
8 changes: 8 additions & 0 deletions osu.Framework/Platform/OsuTKWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ public void Raise()
{
}

public void Flash(bool _)
{
}

public void CancelFlash()
{
}

public abstract bool Focused { get; }

public abstract IBindable<bool> IsActive { get; }
Expand Down
21 changes: 21 additions & 0 deletions osu.Framework/Platform/SDL2Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,27 @@ public void Raise() => ScheduleCommand(() =>
SDL.SDL_RaiseWindow(SDLWindowHandle);
});

public void Flash(bool flashUntilFocused = false) => ScheduleCommand(() =>
{
if (isActive.Value)
return;
if (!RuntimeInfo.IsDesktop)
return;
SDL.SDL_FlashWindow(SDLWindowHandle, flashUntilFocused
? SDL.SDL_FlashOperation.SDL_FLASH_UNTIL_FOCUSED
: SDL.SDL_FlashOperation.SDL_FLASH_BRIEFLY);
});

public void CancelFlash() => ScheduleCommand(() =>
{
if (!RuntimeInfo.IsDesktop)
return;
SDL.SDL_FlashWindow(SDLWindowHandle, SDL.SDL_FlashOperation.SDL_FLASH_CANCEL);
});

/// <summary>
/// Attempts to set the window's icon to the specified image.
/// </summary>
Expand Down

0 comments on commit 9c5cf1d

Please sign in to comment.