--from-toast & GetTickCount64()

This commit is contained in:
Carlos Zamora
2026-04-29 14:40:33 -07:00
parent b53ccb853e
commit 54009e1305
4 changed files with 15 additions and 16 deletions

View File

@@ -1069,10 +1069,10 @@ int AppCommandlineArgs::ParseArgs(winrt::array_view<const winrt::hstring> args)
}
// When a toast notification is clicked, Windows may launch a new instance
// with "__fromToast" as the argument. This is a no-op sentinel — the
// with "--from-toast" as the argument. This is a no-op sentinel — the
// in-process Activated handler on the toast already handled activation.
// See DesktopNotification.cpp for more details.
if (args.size() == 2 && args[1] == L"__fromToast")
if (args.size() == 2 && args[1] == L"--from-toast")
{
return 0;
}

View File

@@ -11,7 +11,7 @@ using namespace winrt::Windows::Data::Xml::Dom;
namespace winrt::TerminalApp::implementation
{
std::atomic<int64_t> DesktopNotification::_lastNotificationTime{ 0 };
std::atomic<uint64_t> DesktopNotification::_lastNotificationTime{ 0 };
// Method Description:
// - Rate-limits toast notifications so we don't spam the user.
@@ -19,12 +19,12 @@ namespace winrt::TerminalApp::implementation
// - Returns true if a notification is allowed, false if too recent.
bool DesktopNotification::ShouldSendNotification()
{
FILETIME ft{};
GetSystemTimeAsFileTime(&ft);
const auto now = (static_cast<int64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
const auto now = GetTickCount64();
auto last = _lastNotificationTime.load(std::memory_order_relaxed);
if (now - last < MinNotificationIntervalTicks)
// Subtraction wraps cleanly modulo 2^64, so the delta is correct even
// across the (~584 million year) GetTickCount64 rollover.
if (now - last < MinNotificationIntervalMs)
{
return false;
}
@@ -53,7 +53,7 @@ namespace winrt::TerminalApp::implementation
// Build the toast XML. We use a simple template with a title and body text.
//
// <toast launch="__fromToast">
// <toast launch="--from-toast">
// <visual>
// <binding template="ToastGeneric">
// <text>Title</text>
@@ -74,9 +74,9 @@ namespace winrt::TerminalApp::implementation
// When a toast is clicked, Windows launches a new instance of the app
// with the "launch" attribute as command-line arguments. We handle
// toast activation in-process via the Activated event below, so the
// new instance should do nothing. "__fromToast" is recognized by
// new instance should do nothing. "--from-toast" is recognized by
// AppCommandlineArgs::ParseArgs as a no-op sentinel.
toastElement.SetAttribute(L"launch", L"__fromToast");
toastElement.SetAttribute(L"launch", L"--from-toast");
toastElement.SetAttribute(L"scenario", L"default");

View File

@@ -29,10 +29,9 @@ namespace winrt::TerminalApp::implementation
static void SendNotification(const DesktopNotificationArgs& args, std::function<void()> activatedFunc);
private:
static std::atomic<int64_t> _lastNotificationTime;
static std::atomic<uint64_t> _lastNotificationTime;
// Minimum interval between notifications, in 100ns ticks (FILETIME units).
// 5 seconds = 5 * 10,000,000
static constexpr int64_t MinNotificationIntervalTicks = 50'000'000LL;
// Minimum interval between notifications, in milliseconds (GetTickCount64 units).
static constexpr uint64_t MinNotificationIntervalMs = 5'000;
};
}

View File

@@ -1029,10 +1029,10 @@ LRESULT WindowEmperor::_messageHandler(HWND window, UINT const message, WPARAM c
const auto handoff = deserializeHandoffPayload(static_cast<const uint8_t*>(cds->lpData), static_cast<const uint8_t*>(cds->lpData) + cds->cbData);
const auto argv = commandlineToArgArray(handoff.args.c_str());
// When a toast notification is clicked, Windows launches a new
// wt.exe with "__fromToast". That instance hands off here via
// wt.exe with "--from-toast". That instance hands off here via
// WM_COPYDATA. We already handle activation in-process via the
// toast's Activated event, so just ignore this handoff.
if (argv.size() != 2 || argv[1] != L"__fromToast")
if (argv.size() != 2 || argv[1] != L"--from-toast")
{
_dispatchCommandlineCommon(argv, handoff.cwd, handoff.env, handoff.show);
}