Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSX: Handle applicationShouldTerminate #6174

Merged
merged 12 commits into from
Jul 26, 2021
6 changes: 6 additions & 0 deletions native/Avalonia.Native/src/OSX/app.mm
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ - (void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)ur

_events->FilesOpened(array);
}

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
return _events->TryShutdown() ? NSTerminateNow : NSTerminateCancel;
}

@end

@interface AvnApplication : NSApplication
Expand Down
13 changes: 1 addition & 12 deletions native/Avalonia.Native/src/OSX/window.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1887,18 +1887,7 @@ -(double) getExtendedTitleBarHeight

+(void)closeAll
{
NSArray<NSWindow*>* windows = [NSArray arrayWithArray:[NSApp windows]];
auto numWindows = [windows count];

for(int i = 0; i < numWindows; i++)
{
auto window = (AvnWindow*)[windows objectAtIndex:i];

if([window parentWindow] == nullptr) // Avalonia will handle the child windows.
{
[window performClose:nil];
}
}
[[NSApplication sharedApplication] terminate:self];
grokys marked this conversation as resolved.
Show resolved Hide resolved
}

- (void)performClose:(id)sender
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using Avalonia.Controls;
Expand Down Expand Up @@ -42,7 +43,7 @@ public ClassicDesktopStyleApplicationLifetime()
"Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed");
_activeLifetime = this;
}

/// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
/// <inheritdoc/>
Expand Down Expand Up @@ -111,6 +112,11 @@ public int Start(string[] args)
((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);
Expand All @@ -123,6 +129,14 @@ public void Dispose()
if (_activeLifetime == this)
_activeLifetime = null;
}

private void ShutdownRequested(object sender, CancelEventArgs e)
{
foreach (var w in Windows)
w.Close();
grokys marked this conversation as resolved.
Show resolved Hide resolved
if (Windows.Count > 0)
e.Cancel = true;
}
}

public class ClassicDesktopStyleApplicationLifetimeOptions
Expand Down
16 changes: 16 additions & 0 deletions src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 1 deletion src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 1 deletion src/Avalonia.Native/AvaloniaNativePlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ void DoInitialize(AvaloniaNativePlatformOptions options)
.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)
{
Expand Down
1 change: 1 addition & 0 deletions src/Avalonia.Native/avn.idl
Original file line number Diff line number Diff line change
Expand Up @@ -732,4 +732,5 @@ interface IAvnNativeControlHostTopLevelAttachment : IUnknown
interface IAvnApplicationEvents : IUnknown
{
void FilesOpened (IAvnStringArray* urls);
bool TryShutdown();
}