Add notification tray icon (boss key)
This PR adds support for creating/removing notification tray icons, needed for boss key support.
This implementation is windows-only, i have a linux one half working but it'll be its own separate patch.
On windows, notification tray icons are closely intertwined with windowing logic, so i had to add 2 methods to IWindow to handle that.
osu!-side PR: https://github.com/ppy/osu/pull/28972
https://github.com/user-attachments/assets/27f1c4f2-09d9-4742-bf0b-641dc3a94fd4
In my testing there's a problem with hiding the game window, and it looks like there's 2 windows, one that gets hidden and the other that remains, but i don't know if that's a framework issue or an osu! side issue.
https://github.com/user-attachments/assets/254eb751-b93b-483a-905d-779fe20a3098
EDIT: this only happens in fullscreen, borderless and windowed work just fine.
SDL recently added tray icon support for windows, unix and macos. Documentation here: https://wiki.libsdl.org/SDL3/CategoryTray.
Using this API gets us the other two platforms for free.
that's awesome, i'll start using it then
fixed conflicts, will now switch to the SDL3 API
I think the API should be declarative, and make use of the SDL tray menu nesting.
public interface IDesktopWindow : IWindow
{
// dispose to remove the tray icon
IDisposable CreateTrayIcon(TrayIcon icon);
}
static void Main()
{
IWindow window;
if (window is IDesktopWindow desktopWindow)
{
var icon = new TrayIcon
{
Label = "osu!",
Icon = imageSharpImage,
Menu = new TrayMenuEntry[]
{
new TrayButton
{
Label = "Open osu!",
Default = true, // label should be in bold and double-clicking the icon will invoke this action
Action = () => openOsuAndDisposeTray(),
},
new TraySubmenu
{
Label = "Example submenu",
Entries = new TrayMenuEntry[]
{
new TrayCheckbox
{
Checked = true,
Action = b => Logger.Log(b ? "checked" : "unchecked"),
}
}
},
new TraySeparator(),
new TrayButton
{
Label = "Exit",
Action = () => closeTheGameAndDisposeTray(),
}
}
}
var activeTrayIcon = desktopWindow.CreateTrayIcon(icon)
}
}
We just walk the tree and call the appropriate SDL functions in order. The created tray icon and menu are readonly, a game can delete the old menu and create a new one if updates are needed.
I might take a stab at it next year.
yes, actually it's exactly the design i first had in mind when i started working on this many months ago.
when i get home tomorrow i'll get it all working and up to snuff
alright got it to mostly work in a local branch, but the new version of ppy.SDL3-CS isn't released yet so it only works with a local nuget package
alright, rebased on master and made use of the SDL3 API. things are working (tested on windows and linux), but still in a state of flux (the icon isn't set at the moment, and to make things work i had to make ISDLWindow public, which is very much not ideal