Browse Source

Merge pull request #6310 from AvaloniaUI/features/win32-allow-cancel-app-shutdown

Features/win32 allow cancel app shutdown
# Conflicts:
#	src/Avalonia.Controls/ApiCompatBaseline.txt
release/0.10.7
Dan Walmsley 5 years ago
parent
commit
c7bd2ba7b9
  1. 6
      src/Avalonia.Controls/ApiCompatBaseline.txt
  2. 4
      src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
  3. 17
      src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
  4. 9
      src/Avalonia.Controls/ApplicationLifetimes/ShutdownRequestedEventArgs.cs
  5. 3
      src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs
  6. 5
      src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs
  7. 27
      src/Windows/Avalonia.Win32/Win32Platform.cs
  8. 2
      tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs

6
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -1,9 +1,9 @@
Compat issues with assembly Avalonia.Controls:
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseClosed()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseOpening()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.EventHandler<System.ComponentModel.CancelEventArgs> Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.ShutdownRequested' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.add_ShutdownRequested(System.EventHandler<System.ComponentModel.CancelEventArgs>)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.remove_ShutdownRequested(System.EventHandler<System.ComponentModel.CancelEventArgs>)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.EventHandler<Avalonia.Controls.ApplicationLifetimes.ShutdownRequestedEventArgs> Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.ShutdownRequested' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.add_ShutdownRequested(System.EventHandler<Avalonia.Controls.ApplicationLifetimes.ShutdownRequestedEventArgs>)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.remove_ShutdownRequested(System.EventHandler<Avalonia.Controls.ApplicationLifetimes.ShutdownRequestedEventArgs>)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public System.Action<Avalonia.Size> Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.set(System.Action<Avalonia.Size>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.

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

@ -48,7 +48,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup;
/// <inheritdoc/>
public event EventHandler<CancelEventArgs> ShutdownRequested;
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
/// <inheritdoc/>
public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit;
@ -134,7 +134,7 @@ namespace Avalonia.Controls.ApplicationLifetimes
_activeLifetime = null;
}
private void OnShutdownRequested(object sender, CancelEventArgs e)
private void OnShutdownRequested(object sender, ShutdownRequestedEventArgs e)
{
ShutdownRequested?.Invoke(this, e);

17
src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs

@ -37,14 +37,21 @@ namespace Avalonia.Controls.ApplicationLifetimes
IReadOnlyList<Window> Windows { get; }
/// <summary>
/// Raised by the platform when a shutdown is requested.
/// Raised by the platform when an application shutdown is requested.
/// </summary>
/// <remarks>
/// Raised on on OSX via the Quit menu or right-clicking on the application icon and selecting Quit. This event
/// provides a first-chance to cancel application shutdown; if shutdown is not canceled at this point the application
/// Application Shutdown can be requested for various reasons like OS shutdown.
///
/// On Windows this will be called when an OS Session (logout or shutdown) terminates. Cancelling the eventargs will
/// block OS shutdown.
///
/// On OSX this has the same behavior as on Windows and in addition:
/// This event is raised via the Quit menu or right-clicking on the application icon and selecting Quit.
///
/// This event provides a first-chance to cancel application shutdown; if shutdown is not canceled at this point the application
/// will try to close each non-owned open window, invoking the <see cref="Window.Closing"/> event on each and allowing
/// each window to cancel the shutdown.
/// each window to cancel the shutdown of the application. Windows cannot however prevent OS shutdown.
/// </remarks>
event EventHandler<CancelEventArgs> ShutdownRequested;
event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
}
}

9
src/Avalonia.Controls/ApplicationLifetimes/ShutdownRequestedEventArgs.cs

@ -0,0 +1,9 @@
using System.ComponentModel;
namespace Avalonia.Controls.ApplicationLifetimes
{
public class ShutdownRequestedEventArgs : CancelEventArgs
{
}
}

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

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using Avalonia.Controls.ApplicationLifetimes;
namespace Avalonia.Platform
{
@ -11,6 +12,6 @@ namespace Avalonia.Platform
/// <remarks>
/// Raised on on OSX via the Quit menu or right-clicking on the application icon and selecting Quit.
/// </remarks>
event EventHandler<CancelEventArgs> ShutdownRequested;
event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
}
}

5
src/Avalonia.Native/AvaloniaNativeApplicationPlatform.cs

@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Native.Interop;
using Avalonia.Platform;
@ -7,7 +8,7 @@ namespace Avalonia.Native
{
internal class AvaloniaNativeApplicationPlatform : CallbackBase, IAvnApplicationEvents, IPlatformLifetimeEventsImpl
{
public event EventHandler<CancelEventArgs> ShutdownRequested;
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
void IAvnApplicationEvents.FilesOpened(IAvnStringArray urls)
{
@ -17,7 +18,7 @@ namespace Avalonia.Native
public int TryShutdown()
{
if (ShutdownRequested is null) return 1;
var e = new CancelEventArgs();
var e = new ShutdownRequestedEventArgs();
ShutdownRequested(this, e);
return (!e.Cancel).AsComBool();
}

27
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -6,18 +6,16 @@ using System.IO;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Win32;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
@ -65,7 +63,7 @@ namespace Avalonia
namespace Avalonia.Win32
{
class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader
class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader, IPlatformLifetimeEventsImpl
{
private static readonly Win32Platform s_instance = new Win32Platform();
private static Thread _uiThread;
@ -115,7 +113,8 @@ namespace Avalonia.Win32
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IPlatformIconLoader>().ToConstant(s_instance)
.Bind<NonPumpingLockHelper.IHelperImpl>().ToConstant(new NonPumpingSyncContext.HelperImpl())
.Bind<IMountedVolumeInfoProvider>().ToConstant(new WindowsMountedVolumeInfoProvider());
.Bind<IMountedVolumeInfoProvider>().ToConstant(new WindowsMountedVolumeInfoProvider())
.Bind<IPlatformLifetimeEventsImpl>().ToConstant(s_instance);
Win32GlManager.Initialize();
@ -200,6 +199,8 @@ namespace Avalonia.Win32
public event Action<DispatcherPriority?> Signaled;
public event EventHandler<ShutdownRequestedEventArgs> ShutdownRequested;
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]
private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
@ -207,6 +208,22 @@ namespace Avalonia.Win32
{
Signaled?.Invoke(null);
}
if(msg == (uint)WindowsMessage.WM_QUERYENDSESSION)
{
if (ShutdownRequested != null)
{
var e = new ShutdownRequestedEventArgs();
ShutdownRequested(this, e);
if(e.Cancel)
{
return IntPtr.Zero;
}
}
}
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
}

2
tests/Avalonia.Controls.UnitTests/DesktopStyleApplicationLifetimeTests.cs

@ -232,7 +232,7 @@ namespace Avalonia.Controls.UnitTests
++raised;
};
lifetimeEvents.Raise(x => x.ShutdownRequested += null, new CancelEventArgs());
lifetimeEvents.Raise(x => x.ShutdownRequested += null, new ShutdownRequestedEventArgs());
Assert.Equal(1, raised);
Assert.Equal(new[] { window }, lifetime.Windows);

Loading…
Cancel
Save