Skip to content

Handling toast events properly #9

@ysfchn

Description

@ysfchn

Windows provides three event listeners for notifications, "dismissed", "activated" and "failed". And the way of these events work is questionable, if you ask me.

At the time of writing this issue (meaning version 0.2.0 and below), Toasted handles the first invoked event, and ignored others, so there isn't a way to tell if user has "activated" the toast after "dismissing" it - which it turns out it is a valid case.

A toast is considered "dismissed" (thus, Windows invoking the "dismiss" event) for three reasons:

  • UserCanceled — User clicks the "X" button in corner of the toast.
  • ApplicationHidden — Application hides the toast programmatically.
  • TimedOut — User didn't interact with the toast in time, so the toast got faded out on its own.

If a toast was dismissed manually by X button when it appeared on the desktop, the toast is not removed, instead, it will get moved to Action Center where previously received toasts can be seen, and Windows will report the reason as UserCanceled, which is obviously expected according to above.

However, toasts in Action Center do still receive events even if was dismissed before, so that's where things get start interesting. The toast may be dismissed before (timed out or manual X button), but if toast was to get dismissed again, this time from Action Center, the "dismissed" event will be invoked again with the reason of UserCanceled. Which makes us to not be able to tell if the toast was really removed or just pushed to Action Center.

Toasted is made for one-off operations, and does not intend to provide a full blown framework built around Windows. And since it is made for Python, I don't think it would fit in Python to require subscribing to each toast event like in C#. So, to overcome that, Toasted has been listening the events internally and would return a single result obtained from these three events whichever got invoked first.

However, since it is now clear that an event can get invoked more than once with the reasons above, Toasted returning a result early causes to break the potential use cases, so I'm working on to restructure the whole event handling stuff so that Toasted would keep the up-to-date state of the toast internally, and return the reference of the state object instead, so it can stay updated.

Initially, I thought that if I could check for a second "dismissed" event, then I could determine whether it had actually been removed from the Action Center. But then, I realized when a notification is hidden programmatically, toast will no longer exist, and you won't get a second event at all since the first "dismissed" event already indicates it was for ApplicationHidden. Even with that, if you hide a toast that is already completely removed (not showing in Action Center), you will still receive an "dismissed" event, which makes me to believe simply relying on the invoked events may not reliable to know what happened with the toast, so the solution would be to pull the previously sent toasts instead, which wasn't what I've imagined, but I guess that is the only way.

A new release containing said changes should be here in upcoming days if things go well.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions