diff --git a/src/Runner/Helpers/SettingsHelper.cs b/src/Runner/Helpers/SettingsHelper.cs
index 8a2094c403..2b5a20c579 100644
--- a/src/Runner/Helpers/SettingsHelper.cs
+++ b/src/Runner/Helpers/SettingsHelper.cs
@@ -10,6 +10,7 @@ using System.Globalization;
using System.IO;
using System.IO.Pipelines;
using System.Linq;
+using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading;
@@ -125,7 +126,9 @@ namespace RunnerV2.Helpers
break;
case "check_for_updates":
- UpdateSettingsHelper.TriggerUpdateCheck();
+ var version = Assembly.GetExecutingAssembly().GetName().Version!;
+ var versionString = "v" + version.Major + "." + version.Minor + "." + version.Build;
+ UpdateSettingsHelper.TriggerUpdateCheck((version) => { PowerToys.Interop.Notifications.ShowUpdateAvailableNotification("PowerToys", "An update to PowerToys is available.\n" + versionString + " \u2192 " + version, "PTUpdateNotifyTag", "Update Now", "More info..."); });
break;
case "request_update_state_date":
JsonObject response = [];
diff --git a/src/Runner/Program.cs b/src/Runner/Program.cs
index 968759e685..23aa722e15 100644
--- a/src/Runner/Program.cs
+++ b/src/Runner/Program.cs
@@ -52,8 +52,17 @@ internal sealed class Program
case SpecialMode.CouldntToggleFileExplorerModulesNotification:
Environment.Exit(NotificationHelper.DisableToast(NotificationHelper.ToastType.CouldntToggleFileExplorerModules) ? 1 : 0);
return;
+ case SpecialMode.Win32ToastNotificationCOMServer:
+ PowerToys.Interop.Notifications.RunDesktopAppActivatorLoop();
+ return;
+ case SpecialMode.ReportSuccessfulUpdate:
+ PowerToys.Interop.Notifications.RemoveToastsByTag("PTUpdateNotifyTag");
+ PowerToys.Interop.Notifications.RemoveAllScheduledToasts();
+ PowerToys.Interop.Notifications.ShowToastWithActivation("PowerToys was updated successfully", "PowerToys", "PTUpdateNotifyTag");
+ return;
default:
- throw new NotImplementedException("Special modes are not implemented yet.");
+ Logger.LogError("Unexpected special mode detected");
+ return;
}
// If PowerToys restarted the old process may still be around
@@ -159,6 +168,16 @@ internal sealed class Program
/// The the app should run in.
private static SpecialMode ShouldRunInSpecialMode(string[] args)
{
+ if (args.Contains("-ToastActivated"))
+ {
+ return SpecialMode.Win32ToastNotificationCOMServer;
+ }
+
+ if (args.Contains("-report_update_success"))
+ {
+ return SpecialMode.ReportSuccessfulUpdate;
+ }
+
if (args.Length > 0 && args[0].StartsWith("powertoys://", StringComparison.InvariantCultureIgnoreCase))
{
Uri uri = new(args[0]);
diff --git a/src/Runner/Runner.cs b/src/Runner/Runner.cs
index eb2e0ee9c6..7d91f0b1fc 100644
--- a/src/Runner/Runner.cs
+++ b/src/Runner/Runner.cs
@@ -150,7 +150,14 @@ namespace RunnerV2
continue;
}
- HandleMessage(msg.HWnd, msg.Message, (nint)msg.WParam, (nint)msg.LParam);
+ try
+ {
+ HandleMessage(msg.HWnd, msg.Message, (nint)msg.WParam, (nint)msg.LParam);
+ }
+ catch (Exception e)
+ {
+ Logger.LogError("Uncaught error in message handling: ", e);
+ }
}
Close();
diff --git a/src/Update/Program.cs b/src/Update/Program.cs
index deeb281c86..1c50d3349c 100644
--- a/src/Update/Program.cs
+++ b/src/Update/Program.cs
@@ -76,7 +76,7 @@ internal sealed partial class Program
private static async Task PerformUpdateNowStage1()
{
- UpdateSettingsHelper.TriggerUpdateCheck();
+ UpdateSettingsHelper.TriggerUpdateCheck((_) => { });
UpdateSettingsHelper.UpdateInfo updateInfo = await UpdateSettingsHelper.GetUpdateAvailableInfo();
if (updateInfo is not UpdateSettingsHelper.UpdateInfo.UpdateAvailable ua)
diff --git a/src/Update/UpdateSettingsHelper.cs b/src/Update/UpdateSettingsHelper.cs
index 3a2cb94092..ca81f2868a 100644
--- a/src/Update/UpdateSettingsHelper.cs
+++ b/src/Update/UpdateSettingsHelper.cs
@@ -24,7 +24,7 @@ namespace Update
private const string INSTALLERFILENAME = "powertoyssetup";
private const string USERINSTALLERFILENAME = "powertoysusersetup";
- public static void TriggerUpdateCheck()
+ public static void TriggerUpdateCheck(Action doIfUpdateAvailable)
{
if (_updateThread is not null && _updateThread.IsAlive)
{
@@ -41,6 +41,7 @@ namespace Update
break;
case UpdateInfo.UpdateAvailable ua:
ProcessUpdateAvailable(ua);
+ doIfUpdateAvailable($"v{ua.AvailableVersion.Major}.{ua.AvailableVersion.Minor}.{ua.AvailableVersion.Build}");
break;
case UpdateInfo.NoUpdateAvailable:
ProcessNoUpdateAvailable();
@@ -86,11 +87,11 @@ namespace Update
return new UpdateInfo.NoUpdateAvailable();
}
- if (currentVersion is { Major: 0, Minor: 0 })
+ /*if (currentVersion is { Major: 0, Minor: 0 })
{
// Pre-release or local build, skip update check
return new UpdateInfo.NoUpdateAvailable();
- }
+ }*/
try
{
diff --git a/src/Version.props b/src/Version.props
index 2042a73fbd..885970918d 100644
--- a/src/Version.props
+++ b/src/Version.props
@@ -1,7 +1,7 @@
- 0.0.1
+ 0.1.1
Local
diff --git a/src/common/ManagedCommon/Logger.cs b/src/common/ManagedCommon/Logger.cs
index 1e71e06969..924bf3bd2f 100644
--- a/src/common/ManagedCommon/Logger.cs
+++ b/src/common/ManagedCommon/Logger.cs
@@ -186,14 +186,20 @@ namespace ManagedCommon
private static void Log(string message, string type, string memberName, string sourceFilePath, int sourceLineNumber)
{
- Trace.WriteLine("[" + DateTime.Now.TimeOfDay + "] [" + type + "] " + GetCallerInfo(memberName, sourceFilePath, sourceLineNumber));
- Trace.Indent();
- if (message != string.Empty)
+ try
{
- Trace.WriteLine(message);
- }
+ Trace.WriteLine("[" + DateTime.Now.TimeOfDay + "] [" + type + "] " + GetCallerInfo(memberName, sourceFilePath, sourceLineNumber));
+ Trace.Indent();
+ if (message != string.Empty)
+ {
+ Trace.WriteLine(message);
+ }
- Trace.Unindent();
+ Trace.Unindent();
+ }
+ catch
+ {
+ }
}
private static string GetCallerInfo(string memberName, string sourceFilePath, int sourceLineNumber)
diff --git a/src/common/interop/Notifications.cpp b/src/common/interop/Notifications.cpp
new file mode 100644
index 0000000000..35fda162ac
--- /dev/null
+++ b/src/common/interop/Notifications.cpp
@@ -0,0 +1,50 @@
+#include "pch.h"
+#include "Notifications.h"
+#include "Notifications.g.cpp"
+#include "../notifications/notifications.h"
+
+namespace winrt::PowerToys::Interop::implementation
+{
+ using namespace winrt::Windows::Foundation;
+ void Notifications::ShowToast(hstring const& title, hstring const& content)
+ {
+ notifications::show_toast(title.c_str(), content.c_str());
+ }
+
+ void Notifications::RemoveToastsByTag(hstring const& tag)
+ {
+ notifications::remove_toasts_by_tag(tag.c_str());
+ }
+
+ void Notifications::RemoveAllScheduledToasts()
+ {
+ notifications::remove_all_scheduled_toasts();
+ }
+
+ void Notifications::ShowToastWithActivation(hstring const& title, hstring const& content, hstring const& tag)
+ {
+ notifications::toast_params params;
+ params.tag = tag.c_str();
+ notifications::show_toast(title.c_str(), content.c_str(), params);
+ }
+
+ void Notifications::ShowUpdateAvailableNotification(hstring const& title, hstring const& content, hstring const& tag, hstring const& updateNowString, hstring const& openOverviewString) {
+ notifications::toast_params params;
+ params.tag = tag.c_str();
+
+ notifications::show_toast_with_activations(std::move(content.c_str()),
+ title.c_str(),
+ {},
+ { notifications::link_button{ updateNowString.c_str(),
+ L"powertoys://update_now/" },
+ notifications::link_button{ openOverviewString.c_str(),
+ L"powertoys://open_overview/" } },
+ std::move(params),
+ L"powertoys://open_overview/");
+ }
+
+ void Notifications::RunDesktopAppActivatorLoop()
+ {
+ notifications::run_desktop_app_activator_loop();
+ }
+}
diff --git a/src/common/interop/Notifications.h b/src/common/interop/Notifications.h
new file mode 100644
index 0000000000..f22cbf0e13
--- /dev/null
+++ b/src/common/interop/Notifications.h
@@ -0,0 +1,26 @@
+#pragma once
+#include "Notifications.g.h"
+
+#include "../notifications/notifications.h"
+
+namespace winrt::PowerToys::Interop::implementation
+{
+ using namespace winrt::Windows::Foundation;
+
+ struct Notifications : NotificationsT
+ {
+ static void ShowToast(hstring const& title, hstring const& content);
+ static void RemoveToastsByTag(hstring const& tag);
+ static void RemoveAllScheduledToasts();
+ static void ShowToastWithActivation(hstring const& title, hstring const& content, hstring const& tag);
+ static void RunDesktopAppActivatorLoop();
+ static void ShowUpdateAvailableNotification(hstring const& title, hstring const& content, hstring const& tag, hstring const& updateNowString, hstring const& openOverviewString);
+ };
+}
+
+namespace winrt::PowerToys::Interop::factory_implementation
+{
+ struct Notifications : NotificationsT
+ {
+ };
+}
diff --git a/src/common/interop/Notifications.idl b/src/common/interop/Notifications.idl
new file mode 100644
index 0000000000..bffbf41366
--- /dev/null
+++ b/src/common/interop/Notifications.idl
@@ -0,0 +1,17 @@
+namespace PowerToys
+{
+ namespace Interop
+ {
+ [default_interface] runtimeclass Notifications
+ {
+ static void ShowToast(String title, String content);
+ static void RemoveToastsByTag(String tag);
+ static void RemoveAllScheduledToasts();
+ static void ShowToastWithActivation(String title, String content, String tag);
+ static void RunDesktopAppActivatorLoop();
+ static void ShowUpdateAvailableNotification(String title, String content, String tag, String updateNowString, String openOverviewString);
+ }
+ }
+}
+
+
diff --git a/src/common/interop/PowerToys.Interop.vcxproj b/src/common/interop/PowerToys.Interop.vcxproj
index 823957a4c7..5e2c91de35 100644
--- a/src/common/interop/PowerToys.Interop.vcxproj
+++ b/src/common/interop/PowerToys.Interop.vcxproj
@@ -113,6 +113,7 @@
LayoutMapManaged.idl
+
@@ -144,6 +145,7 @@
LayoutMapManaged.idl
+
Create
@@ -176,6 +178,7 @@
+
@@ -184,6 +187,9 @@
{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+ {1d5be09d-78c0-4fd7-af00-ae7c1af7c525}
+