SDL_UnregisterTray unexpectedly triggers SDL_EVENT_QUIT event (Create/Destroy tray for feature detection)
SDL: 3.2.10
The problem
I have logic in my Zig application where I create a tray with SDL_CreateTray and then destroy it with SDL_DestroyTray on start-up to detect if the operating system supports the feature.
Calling SDL_DestroyTray has unexpected behaviour where it calls SDL_UnregisterTray which sends an SDL_EVENT_QUIT event because it detects that are no more windows active and it immediately closes the application on the first-frame.
https://github.com/libsdl-org/SDL/blob/d4cda5105779b34201be7ef2b3e5e2bf85a78876/src/tray/SDL_tray_utils.c#L64-L66
Workarounds for others that find this
- If you want to do this check, create your application window first.
- Temporarily disable the hint
SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSEhttps://github.com/libsdl-org/SDL/blob/d4cda5105779b34201be7ef2b3e5e2bf85a78876/src/tray/SDL_tray_utils.c#L48-L50
Proposed solutions
- A new function to detect if trays are supported.
SDL_HasTraySupportor something. - Avoid triggering quit unless a window has at least been created once or only trigger if the event queue has been polled at least once.
Sending SDL_EVENT_QUIT when closing the last active tray icon when there are no windows is the intended behavior with #11743. I can add a function to check for tray support, I'll look into that shortly.
What's your use case for checking if trays are supported before you'd need one? Generally speaking, you should check if trays are supported only when comes the time to create one you'll need, and either keep it if it works or run the fallback behavior if it doesn't. The reasons are that the situation may have changed (e. g. a Unix user may have installed AppIndicator in the meantime), and that some systems will temporarily show the dummy tray while it exists, which may be confusing for users.
My use-case for checking for tray support is that I want the user to be able to configure whether pressing X on my application will minimize to tray or not.
For Linux/other systems that don't support a tray, I'd rather not show this as an option at all so being able to detect if it can be done or not would be ideal.
Use cases
- If system tray is supported, pressing X (close on the main app window) will create the tray and minimize to it.
- In "Options" screen, if system tray is supported, the user can disable pressing X (close) minimizing the application
Example of feature in Discord
To my understanding of the various system docs, the expected workflow is to create a tray icon when the app starts and keep that one for the process' lifetime, and decide whether to show the related options based on whether the tray icon was created successfully.
I'm not sure if any app only creates a tray icon when the main window is first closed, but if you choose to do this for your app, I would recommend testing across systems to make sure the tray icons react as expected. On my system, the tray bar typically takes a second or two to refresh when an icon is created or removed, which may affect the user experience if tray icons come and go.