Repository: electron/electron
Pull request: feat: support notification priority on Windows

Backport of #50225

See that PR for details.


Notes: Notes: Added support for the `urgency` option in Notifications on Windows.

Changed files:
filename: docs/api/notification.md
patch: @@ -90,11 +90,15 @@ app.whenReady().then(() => {
   * `timeoutType` string (optional) _Linux_ _Windows_ - The timeout duration of the notification. Can be 'default' or 'never'.
   * `replyPlaceholder` string (optional) _macOS_ - The placeholder to write in the inline reply input field.
   * `sound` string (optional) _macOS_ - The name of the sound file to play when the notification is shown.
-  * `urgency` string (optional) _Linux_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
+  * `urgency` string (optional) _Linux_ _Windows_ - The urgency level of the notification. Can be 'normal', 'critical', or 'low'.
   * `actions` [NotificationAction[]](structures/notification-action.md) (optional) _macOS_ - Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation.
   * `closeButtonText` string (optional) _macOS_ - A custom title for the close button of an alert. An empty string will cause the default localized text to be used.
   * `toastXml` string (optional) _Windows_ - A custom description of the Notification on Windows superseding all properties above. Provides full customization of design and behavior of the notification.
 
+> [!NOTE]
+> On Windows, `urgency` type 'critical' sorts the notification higher in Action Center (above default priority notifications), but does not prevent auto-dismissal. To prevent auto-dismissal, you should also set
+> `timeoutType` to 'never'.
+
 ### Instance Events
 
 Objects created with `new Notification` emit the following events:

filename: shell/browser/notifications/notification.h
patch: @@ -45,7 +45,7 @@ struct NotificationOptions {
   std::u16string timeout_type;
   std::u16string reply_placeholder;
   std::u16string sound;
-  std::u16string urgency;  // Linux
+  std::u16string urgency;  // Linux/Windows
   std::vector<NotificationAction> actions;
   std::u16string close_button_text;
   std::u16string toast_xml;

filename: shell/browser/notifications/win/windows_toast_notification.cc
patch: @@ -280,8 +280,9 @@ void WindowsToastNotification::CreateToastNotificationOnBackgroundThread(
   // Continue to create the toast notification
   ComPtr<ABI::Windows::UI::Notifications::IToastNotification>
       toast_notification;
-  if (!CreateToastNotification(toast_xml, notification_id, weak_notification,
-                               ui_task_runner, &toast_notification)) {
+  if (!CreateToastNotification(toast_xml, options, notification_id,
+                               weak_notification, ui_task_runner,
+                               &toast_notification)) {
     return;  // Error already posted to UI thread
   }
 
@@ -349,6 +350,7 @@ bool WindowsToastNotification::CreateToastXmlDocument(
 // returns the created notification via out parameter.
 bool WindowsToastNotification::CreateToastNotification(
     ComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocument> toast_xml,
+    const NotificationOptions& options,
     const std::string& notification_id,
     base::WeakPtr<Notification> weak_notification,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
@@ -416,6 +418,27 @@ bool WindowsToastNotification::CreateToastNotification(
     return false;
   }
 
+  ComPtr<winui::Notifications::IToastNotification4> toast4;
+  hr = (*toast_notification)->QueryInterface(IID_PPV_ARGS(&toast4));
+  if (SUCCEEDED(hr)) {
+    winui::Notifications::ToastNotificationPriority priority =
+        winui::Notifications::ToastNotificationPriority::
+            ToastNotificationPriority_Default;
+    if (options.urgency == u"critical") {
+      priority = winui::Notifications::ToastNotificationPriority::
+          ToastNotificationPriority_High;
+    }
+
+    hr = toast4->put_Priority(priority);
+    if (FAILED(hr)) {
+      std::string err = base::StrCat({"WinAPI: Setting priority failed, ERROR ",
+                                      FailureResultToString(hr)});
+      DebugLog(err);
+      PostNotificationFailedToUIThread(weak_notification, err, ui_task_runner);
+      return false;
+    }
+  }
+
   return true;
 }
 

filename: shell/browser/notifications/win/windows_toast_notification.h
patch: @@ -94,6 +94,7 @@ class WindowsToastNotification : public Notification {
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
   static bool CreateToastNotification(
       ComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocument> toast_xml,
+      const NotificationOptions& options,
       const std::string& notification_id,
       base::WeakPtr<Notification> weak_notification,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,