From 639c7a1e52cb71354cbd4a29eaeda5e4ea1308f8 Mon Sep 17 00:00:00 2001
From: danprice142 <[EMAIL REDACTED]>
Date: Sat, 25 Oct 2025 13:08:57 +0100
Subject: [PATCH] Sdl2 Add support for launchOnExit URI for WinRT
Implements extraction and launching of a 'launchOnExit' URI parameter from protocol activation in SDL_WinRTApp. The URI is stored and launched on app exit, suspension, or window close, enabling return-to-caller scenarios for protocol-activated apps.
---
src/core/winrt/SDL_winrtapp_direct3d.cpp | 66 ++++++++++++++++++++++++
src/core/winrt/SDL_winrtapp_direct3d.h | 1 +
2 files changed, 67 insertions(+)
diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp
index cd9118f2e4241..b251ccb9dc4eb 100644
--- a/src/core/winrt/SDL_winrtapp_direct3d.cpp
+++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp
@@ -20,6 +20,8 @@
*/
#include "../../SDL_internal.h"
+/* Standard C++11 includes: */
+#include <string>
/* Windows includes */
#include "ppltasks.h"
using namespace concurrency;
@@ -84,6 +86,57 @@ SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
// Protocol activation URI storage
static Platform::String^ WINRT_ProtocolActivationURI = nullptr;
+// Store launchOnExit URI separately since WINRT_ProtocolActivationURI gets cleared
+static std::wstring WINRT_LaunchOnExitURI;
+
+// Helper function to extract and store launchOnExit from protocol URI
+static void WINRT_ExtractLaunchOnExitURI(Platform::String^ fullUri)
+{
+ if (fullUri == nullptr)
+ return;
+
+ std::wstring uri(fullUri->Data());
+
+ // Look for launchOnExit parameter in the URI
+ size_t launchPos = uri.find(L"launchOnExit=");
+ if (launchPos == std::wstring::npos)
+ return;
+
+ // Extract the launchOnExit URI value
+ launchPos += 13; // Skip past "launchOnExit="
+ size_t endPos = uri.find(L'&', launchPos);
+ if (endPos == std::wstring::npos)
+ endPos = uri.length();
+
+ std::wstring launchUri = uri.substr(launchPos, endPos - launchPos);
+
+ // URL decode the URI (convert %3A to :, etc.)
+ WINRT_LaunchOnExitURI.clear();
+ for (size_t i = 0; i < launchUri.length(); i++) {
+ if (launchUri[i] == L'%' && i + 2 < launchUri.length()) {
+ wchar_t hex[3] = { launchUri[i + 1], launchUri[i + 2], 0 };
+ WINRT_LaunchOnExitURI += (wchar_t)wcstol(hex, nullptr, 16);
+ i += 2;
+ } else {
+ WINRT_LaunchOnExitURI += launchUri[i];
+ }
+ }
+}
+
+// Helper function to launch URI on exit if protocol activation included launchOnExit parameter
+static void WINRT_LaunchExitUriIfSet()
+{
+ if (!WINRT_LaunchOnExitURI.empty()) {
+ try {
+ // Launch the URI
+ auto uri = ref new Windows::Foundation::Uri(ref new Platform::String(WINRT_LaunchOnExitURI.c_str()));
+ Windows::System::Launcher::LaunchUriAsync(uri);
+ } catch (...) {
+ // Silently ignore errors during termination
+ }
+ }
+}
+
ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
{
public:
@@ -184,6 +237,12 @@ SDL_WinRTApp::SDL_WinRTApp() : m_windowClosed(false),
{
}
+SDL_WinRTApp::~SDL_WinRTApp()
+{
+ // Launch exit URI if set (handles protocol activation returning to caller)
+ WINRT_LaunchExitUriIfSet();
+}
+
void SDL_WinRTApp::Initialize(CoreApplicationView ^ applicationView)
{
applicationView->Activated +=
@@ -605,6 +664,7 @@ void SDL_WinRTApp::OnWindowClosed(CoreWindow ^ sender, CoreWindowEventArgs ^ arg
SDL_Log("%s\n", __FUNCTION__);
#endif
m_windowClosed = true;
+ WINRT_LaunchExitUriIfSet();
}
void SDL_WinRTApp::OnAppActivated(CoreApplicationView ^ applicationView, IActivatedEventArgs ^ args)
@@ -615,6 +675,8 @@ void SDL_WinRTApp::OnAppActivated(CoreApplicationView ^ applicationView, IActiva
if (protocolArgs && protocolArgs->Uri)
{
WINRT_ProtocolActivationURI = protocolArgs->Uri->AbsoluteUri;
+ // Extract and store launchOnExit URI before main URI gets cleared
+ WINRT_ExtractLaunchOnExitURI(WINRT_ProtocolActivationURI);
}
}
CoreWindow::GetForCurrentThread()->Activate();
@@ -622,6 +684,9 @@ void SDL_WinRTApp::OnAppActivated(CoreApplicationView ^ applicationView, IActiva
void SDL_WinRTApp::OnSuspending(Platform::Object ^ sender, SuspendingEventArgs ^ args)
{
+ // Launch exit URI if set before suspending
+ WINRT_LaunchExitUriIfSet();
+
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
@@ -675,6 +740,7 @@ void SDL_WinRTApp::OnResuming(Platform::Object ^ sender, Platform::Object ^ args
void SDL_WinRTApp::OnExiting(Platform::Object ^ sender, Platform::Object ^ args)
{
SDL_SendAppEvent(SDL_APP_TERMINATING);
+ WINRT_LaunchExitUriIfSet();
}
static void WINRT_LogPointerEvent(const char *header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
diff --git a/src/core/winrt/SDL_winrtapp_direct3d.h b/src/core/winrt/SDL_winrtapp_direct3d.h
index c4bfd1d46195b..9d2eb76870f15 100644
--- a/src/core/winrt/SDL_winrtapp_direct3d.h
+++ b/src/core/winrt/SDL_winrtapp_direct3d.h
@@ -26,6 +26,7 @@ ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFramewo
{
public:
SDL_WinRTApp();
+ virtual ~SDL_WinRTApp();
// IFrameworkView Methods.
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView ^ applicationView);