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} +