Fix notification activation and calendar bootstrap flow
This commit is contained in:
+114
-11
@@ -13,38 +13,87 @@ namespace Wino.Mail.WinUI;
|
||||
|
||||
public class Program
|
||||
{
|
||||
private const string AppNotificationActivatedCommandLinePrefix = "----AppNotificationActivated:";
|
||||
private const string SingleInstanceKey = "WinoMailSingleInstance";
|
||||
private const string ForceAlternateModeSignalEventName = "Local\\WinoMailForceAlternateMode";
|
||||
private const string MailHostRunningMutexName = "Local\\WinoMailMailHostRunning";
|
||||
private const int VkControl = 0x11;
|
||||
|
||||
private static bool _forceAlternateModeOnLaunch;
|
||||
private static EventWaitHandle? _forceAlternateModeSignalHandle;
|
||||
private static Mutex? _mailHostRunningMutex;
|
||||
private static PendingBootstrapActivation? _pendingBootstrapActivation;
|
||||
private static bool _hasDeferredAppNotificationStartup;
|
||||
private static bool _shouldRegisterAppNotifications;
|
||||
|
||||
[STAThread]
|
||||
static int Main(string[] args)
|
||||
{
|
||||
WinRT.ComWrappersSupport.InitializeComWrappers();
|
||||
bool isRedirect = DecideRedirection();
|
||||
|
||||
if (TryCaptureCommandLineToastActivation(args))
|
||||
{
|
||||
_shouldRegisterAppNotifications = true;
|
||||
EnsureMailHostRunningMutex();
|
||||
StartApplication();
|
||||
return 0;
|
||||
}
|
||||
|
||||
var activationArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
var shouldBootstrapCalendarEntry = CalendarEntryBootstrapActivation.ShouldBootstrapToMailHost(activationArgs);
|
||||
_shouldRegisterAppNotifications = !shouldBootstrapCalendarEntry;
|
||||
|
||||
if (shouldBootstrapCalendarEntry && !IsMailHostRunning())
|
||||
{
|
||||
if (CalendarEntryBootstrapActivation.QueuePendingActivation(activationArgs) &&
|
||||
CalendarEntryBootstrapActivation.LaunchMailHost())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CalendarEntryBootstrapActivation.ClearPendingActivation();
|
||||
}
|
||||
|
||||
_pendingBootstrapActivation = CalendarEntryBootstrapActivation.ConsumePendingActivation();
|
||||
bool isRedirect = DecideRedirection(activationArgs);
|
||||
|
||||
if (!isRedirect)
|
||||
{
|
||||
Application.Start((p) =>
|
||||
{
|
||||
var context = new DispatcherQueueSynchronizationContext(
|
||||
DispatcherQueue.GetForCurrentThread());
|
||||
SynchronizationContext.SetSynchronizationContext(context);
|
||||
var app = new App();
|
||||
_ = app.HandleInitialActivationAsync();
|
||||
});
|
||||
EnsureMailHostRunningMutex();
|
||||
StartApplication();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static bool DecideRedirection()
|
||||
public static bool ShouldRegisterAppNotifications()
|
||||
=> _shouldRegisterAppNotifications;
|
||||
|
||||
internal static bool TryConsumeDeferredAppNotificationStartup()
|
||||
{
|
||||
if (!_hasDeferredAppNotificationStartup)
|
||||
return false;
|
||||
|
||||
_hasDeferredAppNotificationStartup = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool TryConsumePendingBootstrapActivation(out PendingBootstrapActivation activation)
|
||||
{
|
||||
if (_pendingBootstrapActivation == null)
|
||||
{
|
||||
activation = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
activation = _pendingBootstrapActivation;
|
||||
_pendingBootstrapActivation = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool DecideRedirection(AppActivationArguments args)
|
||||
{
|
||||
bool isRedirect = false;
|
||||
AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
_forceAlternateModeOnLaunch = args.Kind == ExtendedActivationKind.Launch && IsCtrlKeyDown();
|
||||
|
||||
AppInstance keyInstance = AppInstance.FindOrRegisterForKey(SingleInstanceKey);
|
||||
@@ -69,6 +118,60 @@ public class Program
|
||||
return isRedirect;
|
||||
}
|
||||
|
||||
private static bool TryCaptureCommandLineToastActivation(string[] args)
|
||||
{
|
||||
var commandLine = Environment.CommandLine;
|
||||
var prefixIndex = commandLine.IndexOf(AppNotificationActivatedCommandLinePrefix, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (prefixIndex < 0)
|
||||
return false;
|
||||
|
||||
// Do not touch AppInstance.GetActivatedEventArgs here. For app-notification cold starts,
|
||||
// Windows App SDK expects the app to register AppNotificationManager first and then
|
||||
// resolve the activation inside App.OnLaunched.
|
||||
_hasDeferredAppNotificationStartup = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void StartApplication()
|
||||
{
|
||||
Application.Start((p) =>
|
||||
{
|
||||
var context = new DispatcherQueueSynchronizationContext(
|
||||
DispatcherQueue.GetForCurrentThread());
|
||||
SynchronizationContext.SetSynchronizationContext(context);
|
||||
_ = new App();
|
||||
});
|
||||
}
|
||||
|
||||
private static bool IsMailHostRunning()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Mutex.TryOpenExisting(MailHostRunningMutexName, out var existingMutex))
|
||||
return false;
|
||||
|
||||
existingMutex.Dispose();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureMailHostRunningMutex()
|
||||
{
|
||||
try
|
||||
{
|
||||
_mailHostRunningMutex ??= new Mutex(false, MailHostRunningMutexName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_mailHostRunningMutex = null;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr CreateEvent(
|
||||
IntPtr lpEventAttributes, bool bManualReset,
|
||||
|
||||
Reference in New Issue
Block a user