microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.73k stars 310 forks source link

Modern System Tray Icon #713

Open mveril opened 3 years ago

mveril commented 3 years ago

Proposal: Modern System Tray Icon

Summary

After a feature proposal to the WinUI team to make system tray icons with WInUI microsoft/microsoft-ui-xaml#2020 and to have followed this discussion #519 and this proposal #711 I would like to offer my take on what the modern way to create system tray icons should look like. A system-managed tray icon accessible for UWP and WIn32 applications respecting the app lifecycle #111 and offering a UI that respects WinUI standards. We also must take into account that many applications that use the system tray APIs are "service-like" app (that needs 24/7 execution), and so the App Lifecycle API are not suitable in this precise case. The new APIs need to be easy to use on each case.

Rationale

Scope

Capability Priority
This proposal will allow UWP and Win32 developers to create System tray icon even if the app respect the app lifecycle Must
This proposal will allow developers of Win32 "service-like" app that don't follow the standard lifecycle to create System tray icon Must
This proposal will allow UWP and Win32 developers to create System tray icon that respect Windows theme and fluent design Must
This proposal will allow UWP and Win32 developers to interact with the System tray icon from background and foreground Must
This proposal will allow UWP and Win32 developers to launch his app using his System tray icon Must
This proposal will allow UWP and Win32 developers to easily show context menu flyouts associated to the system tray icon Must
This proposal will allow end users to run background tasks using the system tray icon Must
This proposal will allow end users of a service-like Win32 app to interact directly with the service using the system tray icon Must
This proposal will allow end users to interact with the system tray icon using keyboard Must
This proposal will allow developers of Win32 "service-like" app to create System tray icon with the same set of APIs Should
This proposal will allow UWP and Win32 developers to easily show custom flyouts associated to the system tray icon Should
This proposal will allow allow end users to easily interact with the System tray icons using keyboard Should
This proposal will allow end users to control background tasks using the system tray icon Could
This proposal will allow UWP and Win32 developers to show balloon notifications Won't

Important Notes

APIs that could be inspiring

Open Questions

How the new APIs that will be adapted to short-running applications could also be adapted to long running "service-like" apps ?

orcmid commented 3 years ago

As an user, I find the increasing use of system tray icons and keeping apps running in the background to be quite offensive. In particular, too many apps force going to the system tray on close with no user control of the behavior.

  1. Zoom on Windows 10 does it better - it ends up creating a task bar icon that reveals Zoom is still running, and while objectionable, it is easy to notice and to exit it.
  2. My Philips DreamWeaver data card loader, an app I only run once a week, goes to the system tray whether I like it or not (although there is a notification that happened). Then I Have to go kill it. There is absolutely no reason for this application to stay running in the background. And I still use the removable drive removal to ensure that the USB key from my C-PAP can be safely removed.
  3. The change of the Bing Desktop App to just be a Bing Wallpaper app that sits in the system tray is very annoying. That is the only way, now, to find out what the wallpaper image subject is and where to find more information about it. That's a tiny symbol and I have to perform extra work. It keeps me from doing more Bing searches every day. I doubt that shows up in their stats, but I use Bing search less than before.
  4. The Discord app is another offender. I learn that I have left it running by virtue of all the notifications that pop up, until I go into the system tray pop-up and kill it dead.
  5. What makes this even more difficult is apparent absence of a way to force certain apps to have their system tray icon be visible and not hidden in the pop=up of all of them. I made good use of that provision in the past. I can't find it on the currently-supported Windows 10 releases.
ptorr-msft commented 3 years ago

@orcmid presumably a new API would solve those problems:

  1. Users must grant permission for the icon to exist, with a mechanism to manage them after-the-fact, too.
  2. The target app is suspended / terminated, and only woken up when the user interacts with the icon.
mveril commented 3 years ago

@orcmid presumably a new API would solve those problems:

Yes I think

  1. Users must grant permission for the icon to exist, with a mechanism to manage them after-the-fact, too.

Yes but I don't know if Win32 apps should be allowed to enable it by default like startup tasks or not

  1. The target app is suspended / terminated, and only woken up when the user interacts with the icon.

Exactly It's the main interest of this proposal. It's what I called "respect the app lifecycle"

huoyaoyuan commented 3 years ago

System tray icon can also (and commonly) be used for an interface to service-like applications. The application runs background tasks and the icon is active.

orcmid commented 3 years ago

System tray icon can also (and commonly) be used for an interface to service-like applications. The application runs background tasks and the icon is active.

Yes, and I see those. They are not the subject of my complaint.

I am a little bemused that I am not explicitly running any graphical programs but 15 are using my GTX 1060 6GB display adapter. That's an usefull systrap thingie. I am also happy with my password monitor and HyperSnap being there and on the displayed system tray.

I am about to uninstall Skype since most of those calls are now accomplished with Microsoft Teams. Neither Teams nor the "Your Phone" app seem to need residence on the system tray.

I am not so thrilled with Outlook, OneNote, and WinZip taking system folder real-estate though. I'm going to dump the Wnzip and Outlook ones.

riverar commented 3 years ago

The target app is suspended / terminated, and only woken up when the user interacts with the icon.

Our app consists of a flyout that appears when a user clicks a notification area icon. We cannot afford to be suspended and resumed, it must remain running in the background. Because this proposal requires apps to participate in process lifetime management (PLM) without consideration of apps like ours, I must reject this proposal.

ptorr-msft commented 3 years ago

@riverar remember this is Reunion - it's all about options. I should have been clearer in my reply.

The actual requirement listed above is:

This proposal will allow UWP and Win32 developers to create System tray icon that respect the app lifecylce

"respect[ing] app lifecycle" means the app might suspend (if it wants to) or it might not. The problem with Shell_NotifyIcon today is that the app MUST keep running to check window messages; that's a poor design if your app doesn't need to be running 24x7.

riverar commented 3 years ago

@ptorr-msft Hm, I don't agree. @mveril states in their summary (emphasis mine):

A system-managed tray icon accessible for UWP and WIn32 [sic] applications respecting the app lifecycle #111 and offering a UI that respects WinUI standards.

The author further lists the following as a Must:

This proposal will allow UWP and Win32 developers to create System tray icon that respect the app lifecylce [sic]

While the author wrote "will allow", I believe that is in error. It appears the author's intention is to require apps to participate in PLM to take advantage of the proposed enhancements. I don't think that's fair to apps, like ours, that cannot participate in PLM.

Suggested scope changes:

- This proposal will allow UWP and Win32 developers to create System tray icon that respect the app lifecylce | Must
+ New mechanism provides facility for apps participating in PLM to create a modern Notification Area icon | Must
+ New mechanism provides facility for apps not participating in PLM to create a modern Notification Area icon | Must
ptorr-msft commented 3 years ago

If you read the spec for #111, nothing about suspension is mandated. It talks about "allowing" apps to be "notified" which implies they can choose to ignore the notification (or not even register for it). There is no forced "lifecycle" in Reunion, so if @mveril wants this proposal to require suspension, then a different change would be needed to the requirements.

(Direct quote from #111):

All of these are simply informative notifications: the app can do whatever it likes with the information

mveril commented 3 years ago

@riverar Sorry I haven't had time to test your app yet, but if I understand your needs correctly, IMHO it won't be necessary to have an always-on app to display a flyout on click. I don't know if you've paid attention to this but this proposal will allow support for flyouts with an API that might look like the Contact panel. I understand that a lot of apps can't comply with PLM. (Docker, Antivirus and many more ...). You're right, more flexibility is always better, this is "Project Reunion" after all! @ptorr-msft I don't think suspension is needed. after all, suspension is not needed for JumpList. Can you explain your thinking please. I agree with @riverar that the change he propose is needed in the scope. But for clarification what is the definition of PLM ? It's the same as the Reunion app lifecycle or there are some specificity? So what would you imagine from an implementation perspective? Some APIs for app which support PLM with Background tasks and activation events and an alternative in the form of classical events to leave the choice, like the Window class of WinUI which supports both CoreWindow and HWind with certain APIs which are different for each case, or will a single API surface be possible to handle both cases?

mveril commented 3 years ago

@riverar I finally had the time to test your application (very good job ! I think I'll keep it on my system). Here is my conclusion:

Our app consists of a flyout that appears when a user clicks a notification area icon. [...] it must remain running in the background.

With this proposal, it will not be necessary (but must be possible) to have an application always active to display a flyout on click. This functionality should be handled by this proposal (because It is widely used) and the flyout would be created for you. Your job would only be to define the content of the flyout and adjust the size of it. This corresponds to the scope:

This proposal will allow developers to show flyout using the system tray Icon

But in your particular case even if I have no certainty I think that you will still need an always active application to manage the global hot keys but that should absolutely not prevent you from using this feature proposal properly.

ptorr-msft commented 3 years ago

I think the current wording is fine, but you can change if you like (it's your proposal :)).

The problem I believe you want to avoid (I sure do!) is the current requirement for apps to always be running to respond to the tray via the WndProc.

There are two obvious ways to improve on this:

Both should be available in such an API.

mveril commented 3 years ago

@ptorr-msft Yes, that's exactly the goal, but this new API should also be easily accessible for long-running service-like applications like @huoyaoyuan as previously pointed out. Maybe the AppInstance ProjectReunion API proposed by @andreww-msft as part of #111 should be the solution. Anyway I don't think an application using a System tray icon will have any interest in displaying an icon per instance. Either the application will be multi-instance, the icon will be shared. Otherwise the activation event could refer to the instance which created the icon in its properties. What do you think of this solution ?

orcmid commented 3 years ago

What do you think of this solution ?

I am getting the impression that this situation is being over-thought and is maybe over-constrained as well.

Maybe it would be good to elevate from implementation worries to an agreement on the function and utility of the system tray for users, accounting for the degree of Windows using population that has no understanding of it and blissfully ignore notifications too.

As I've already mentioned, I give Zoom great credit for using the task bar to reveal it is running minimized on "close by X" That Discord hides in the system tray, usually out of sight, is very annoying and revealed only when there are notifications about activity in which I have no interest. I know to hunt it down now, but it is making me work too hard. So I guess another higher level consideration has to do with how products might abuse the tray and also its employment for surveillance actions imposed on inexpert users. A counter-example to the Discord case is Hypersnap, which has a clear purpose and that I have enabled that way and continue to use without having to figure out how and whether various releases of Windows 10 have a screen capture arrangement understandable to me.

orcmid commented 3 years ago

... Discord hides in the system tray, usually out of sight, is very annoying and revealed only when there are notifications about activity in which I have no interest. I know to hunt it down now, but it is making me work too hard.

Part of my dismay is that the ability to control what appears in the system tray and system-tray strip od the task bar has disappeared. Duhhh. It turns out that the "system tray" name is not used and the Settings / Personalization / Taskbar / Notification area / Select which icons appear on the taskbar is what I needed instead. Sheesh. OK, working for me. So maybe that is also what we should be calling it and also comprehending the intended use case.

mveril commented 3 years ago

@orcmid sorry for not having answered you earlier but I was very busy with my job this week. You are right, it is important to leave the maximum number of doors open while we find the right scopes. Personally, I don't really like the term 'Notification area' because today balloon notifications are deprecated and replaced by toast notifications. therefore the icons of the system tray no longer fulfill this purpose. Personally, I don't think the main taskbar part is the best place to monitor or report background tasks. If I understood correctly what you said, this is what Zoom does? for me this part is reserved for the foreground apps and the favorite apps. I think that a specific authorization should be requested by the application to display in the system tray as is the case for startup tasks. These tasks could be a good model for the authorization to display its icons. The peculiarity is that the startup tasks does not display a confirmation request for the Win32 model unlike the UWP model. This authorization could be accepted or refused at any time in the settings with the section you are talking about but also in the parameters of each application as can be done with the start-up tasks. Should we ask permission explicitly ? For which app model, UWP or all? Do you think these icons should be completely non-existent when it is off or appearing in the drop-down menu as it is now? Maybe both cases could be handled. This API could also be linked to a specific capability in the manifest to limit abuse. We can also think of a menu item called "Hide" which will allow the user to easily send the icons to the drop-down menu and which will automatically be displayed at the bottom of the icon contextual menu. What will be your wishes for the system tray?

sylveon commented 3 years ago

@orcmid you can also just drag and drop icons to and from the tray overflow instead of going in settings ;)

On to the issue.

I've recently commited work to integrate a UWP MenuFlyout with Shell_NotifyIcon and while it's a bit buggy (in part due to https://github.com/microsoft/microsoft-ui-xaml/issues/3953) it looks pretty solid and modern:

https://cdn.discordapp.com/attachments/660265525124923392/835385558146482196/ttb_rocks.mp4

I suspect one could use any flyout as well, and I plan on trying that in future versions for a better UX and less crashes.

My app is "service-like" so does need 24/7 execution, and I would be interested in replacing the 2000 lines of code this required for something more... Simple to implement.

A few requirements I can think of:

mveril commented 3 years ago

I've recently commited work to integrate a UWP MenuFlyout with Shell_NotifyIcon and while it's a bit buggy (in part due to microsoft/microsoft-ui-xaml#3953) it looks pretty solid and modern:

https://cdn.discordapp.com/attachments/660265525124923392/835385558146482196/ttb_rocks.mp4

I suspect one could use any flyout as well, and I plan on trying that in future versions for a better UX and less crashes.

Very good job @sylveon ! From a UX point of view, this is exactly the goal. Is the app you show in the video open-source? I will be interested to look at the code and test it.

My app is "service-like" so does need 24/7 execution, and I would be interested in replacing the 2000 lines of code this required for something more... Simple to implement.

A few requirements I can think of:

  • support for any flyout, be it MenuFlyout or just a Flyout with custom controls.

It's planned in the scope In fact, there are generally two types of interface:

  • a modern looking tooltip, my implementation does that too :)

Yes, I think the Fluent design must be applied at all levels

  • as mentioned before, does not require processes to opt-in to lifecycle

Yes, this case must be fully supported. Maybe using COM or with some specific APIs.

  • can be strictly bound to a specific application, like Shell_NotifyIcon with a GUID can, but without the requirement to code sign the executable. This has the bonus side effect that if a background app crashes and restarts, the tray icon isn't duplicated ad infinitum

Oh I didn't know it's possible to do that! This is a problem that I have encountered before. This would be even more essential since the icon should be managed by the system and could be eventually used by several successive instances of the same app.

  • support for keyboard only interaction by default (tab navigation from the taskbar to the tray icon and hitting space/enter should open the flyout). While implementing this one thing I noticed is that the amount of apps doing this was... Low. I implemented it because it was a few lines of code more but I can see why it's easy to omit it.

You are right I didn't know it was already possible. An out of the box standardization of keyboard shortcuts would be interesting.

I have updated the scope to reflect your comment. thank you very much ! I'm very happy to see it's possible using Shell_NotifyIcon APIs to create Fluent System tray icon UX with WinUI. This shows the way !

sylveon commented 3 years ago

Yes it's open source! The code is in this commit and you can grab a build to test from Azure Pipelines! The code is licensed under GPLv3, but I don't particularly mind anybody taking inspiration from it.

You'll have to add the following in the configuration file to enable it, since it's still crashy I'm leaving it undocumented and off by default for now:

"experimental": {
    "use_xaml_context_menu": true
}
sylveon commented 2 years ago

In Windows 11, custom tooltips for tray icons seems to be intentionally disabled.

They all look like this, even if your app says it wants to show custom tooltips the taskbar will disregard it: image

VS in Windows 10: image

I left feedback about it here: https://aka.ms/AAd21h2

zadjii-msft commented 2 years ago

In Windows 11, custom tooltips for tray icons seems to be intentionally disabled....

I'm pretty sure this thread isn't the place to follow up with that particular bug, but I'm not totally sure how the WindowsAppSDK team wants to triage their repo. For other internal folks reading this thread, that feedback got parented to MSFT:34113237.

sylveon commented 2 years ago

Was just pointing it out because I've previously talked about my implementation using custom tooltips. Glad to know there's an internal bug for it though!

JaiganeshKumaran commented 2 years ago

One of the problems with notification area icons are that it's primarily an app powered experience which means it needs to run all the time. While many of them are to indicate they are running in the background, some of them just use it to display options. Jumplists could technically be used for a lot of them however now with Windows 11 not showing them in Start, there's less place to access them and jumplists don't indicate an app running in background or not. Notification area icons can continue to be used however instead of apps displaying them, it should be brokered and the options in the context menu, action to do when clicked etc... should be well defined and instead of being part of an UI framework, it should be part of the application model itself. Since the apps only say what options and don't just attach their own menu, Windows can use a more modern UI and refresh anytime with consistency. Today you right click on each third-party system tray icon and see a different design.

JaiganeshKumaran commented 2 years ago

With jumplists, it's not possible to change options dynamically unless you're running all the time. Maybe there could be a way where a background task that updates the options for the current program state.

JaiganeshKumaran commented 2 years ago

System tray icons shouldn't be used if there's no background task or need for quick access to options even without the app opened that refresh dynamically. Some apps like Spotify uses a tray icon as a way to minimize the application when playing music which shouldn't be done as the user doesn't know whether a foreground UI is actually there and will wonder where the sound is coming from. If an app shows a tray icon, it should be shown even without the foreground UI and shouldn't be a companion to it.

HavenDV commented 2 years ago

I want to note for the future that most of this is already implemented in my H.NotifyIcon library. It has an example of a Windowless application, as well as an example of a regular WinUI application with the ability to collapse. It supports the ability to create a native context menu for TrayIcon with animation (still in preview mode) and some other features. The API is accessible from xaml and mostly inherited from hardcodet/wpf-notifyicon for easy transition to WinUI from WPF

AzAgarampur commented 1 year ago

Now that we have Widgets supported by the windows app sdk, is there more of a focus on using that instead of trying to show information by a tray icon? I don't think a widget has superseded a tray icon but it seems like we're now supposed to focus on displaying information outside of an app's foreground via a widget now, right?

Also, I'm not sure but if a widget / the widget board can be disabled completely then we're stuck with using tray icons, unless there is an alternative.

riverar commented 1 year ago

I would certainly hope not. Widgets are not a good substitute for notification area icons. For example, they don't even appear on-screen without opening the Widget Board.