Browse Source

Handle applicationShouldTerminate on OSX.

Added some new plumbing to facilitate this:

- A managed event is raised `IPlatformLifetimeEventsImpl.ShutdownRequested`
- This event is subscribed from `ClassicDesktopStyleApplicationLifetime`
- Which tries to close all windows
- And returns false to cancel the OS-level close if not all windows could be closed
pull/6174/head
Steven Kirk 5 years ago
parent
commit
b71743e9a8
  1. 6
      native/Avalonia.Native/src/OSX/app.mm
  2. 22
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  3. 16
      src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
  4. 13
      src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs
  5. 3
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  6. 1
      src/Avalonia.Native/avn.idl

6
native/Avalonia.Native/src/OSX/app.mm

@ -50,6 +50,12 @@ ComPtr<IAvnApplicationEvents> _events;
_events->FilesOpened(array);
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
return _events->TryShutdown() ? NSTerminateNow : NSTerminateCancel;
}
@end
@interface AvnApplication : NSApplication

22
src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using Avalonia.Controls;
@ -42,7 +43,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
"Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed");
_activeLifetime = this;
}
/// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
/// <inheritdoc/>
@ -111,6 +112,11 @@ namespace Avalonia.Controls.ApplicationLifetimes
((IApplicationPlatformEvents)Application.Current).RaiseUrlsOpened(args);
}
var lifetimeEvents = AvaloniaLocator.Current.GetService<IPlatformLifetimeEventsImpl>();
if (lifetimeEvents != null)
lifetimeEvents.ShutdownRequested += ShutdownRequested;
_cts = new CancellationTokenSource();
MainWindow?.Show();
Dispatcher.UIThread.MainLoop(_cts.Token);
@ -123,6 +129,20 @@ namespace Avalonia.Controls.ApplicationLifetimes
if (_activeLifetime == this)
_activeLifetime = null;
}
private void ShutdownRequested(object sender, CancelEventArgs e)
{
foreach (var w in Windows.ToArray())
w.Close();
if (Windows.Count > 0)
e.Cancel = true;
}
private bool TryCloseAllWindows()
{
return Windows.Count == 0;
}
}
public class ClassicDesktopStyleApplicationLifetimeOptions

16
src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs

@ -0,0 +1,16 @@
using System;
using System.ComponentModel;
namespace Avalonia.Platform
{
public interface IPlatformLifetimeEventsImpl
{
/// <summary>
/// Raised by the platform when a shutdown is requested.
/// </summary>
/// <remarks>
/// Raised on on OSX via the Quit menu or right-clicking on the application icon and selecting Quit.
/// </remarks>
event EventHandler<CancelEventArgs> ShutdownRequested;
}
}

13
src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs

@ -1,14 +1,25 @@
using System;
using System.ComponentModel;
using Avalonia.Native.Interop;
using Avalonia.Platform;
namespace Avalonia.Native
{
internal class AvaloniaNativeApplicationPlatform : CallbackBase, IAvnApplicationEvents
internal class AvaloniaNativeApplicationPlatform : CallbackBase, IAvnApplicationEvents, IPlatformLifetimeEventsImpl
{
public event EventHandler<CancelEventArgs> ShutdownRequested;
void IAvnApplicationEvents.FilesOpened(IAvnStringArray urls)
{
((IApplicationPlatformEvents)Application.Current).RaiseUrlsOpened(urls.ToStringArray());
}
public int TryShutdown()
{
if (ShutdownRequested is null) return 1;
var e = new CancelEventArgs();
ShutdownRequested(this, e);
return (!e.Cancel).AsComBool();
}
}
}

3
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -111,7 +111,8 @@ namespace Avalonia.Native
.Bind<ISystemDialogImpl>().ToConstant(new SystemDialogs(_factory.CreateSystemDialogs()))
.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Meta))
.Bind<IMountedVolumeInfoProvider>().ToConstant(new MacOSMountedVolumeInfoProvider())
.Bind<IPlatformDragSource>().ToConstant(new AvaloniaNativeDragSource(_factory));
.Bind<IPlatformDragSource>().ToConstant(new AvaloniaNativeDragSource(_factory))
.Bind<IPlatformLifetimeEventsImpl>().ToConstant(applicationPlatform);
if (_options.UseGpu)
{

1
src/Avalonia.Native/avn.idl

@ -732,4 +732,5 @@ interface IAvnNativeControlHostTopLevelAttachment : IUnknown
interface IAvnApplicationEvents : IUnknown
{
void FilesOpened (IAvnStringArray* urls);
bool TryShutdown();
}

Loading…
Cancel
Save