From c0ba356a963b053e04d87c47eb52c4bc11812a66 Mon Sep 17 00:00:00 2001 From: lindexi Date: Wed, 18 Jun 2025 00:38:34 +0800 Subject: [PATCH] Fix WindowCloseReason of WindowClosingEventArgs Passed During System Shutdown (#19055) Fix https://github.com/AvaloniaUI/Avalonia/issues/19027 --- .../ClassicDesktopStyleApplicationLifetime.cs | 7 +++++-- .../ShutdownRequestedEventArgs.cs | 5 ++++- src/Avalonia.X11/X11PlatformLifetimeEvents.cs | 7 +++++-- src/Windows/Avalonia.Win32/Win32Platform.cs | 17 ++++++++++++++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs index 37e365ea69..35e63e8ef5 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; @@ -188,7 +188,10 @@ namespace Avalonia.Controls.ApplicationLifetimes if (w.Owner is null) { var ignoreCancel = force || (ShutdownMode == ShutdownMode.OnMainWindowClose && w != MainWindow); - w.CloseCore(WindowCloseReason.ApplicationShutdown, isProgrammatic, ignoreCancel); + var reason = e.IsOSShutdown ? + WindowCloseReason.OSShutdown : + WindowCloseReason.ApplicationShutdown; + w.CloseCore(reason, isProgrammatic, ignoreCancel); } } diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ShutdownRequestedEventArgs.cs b/src/Avalonia.Controls/ApplicationLifetimes/ShutdownRequestedEventArgs.cs index 62bc3a8904..4dd62936df 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ShutdownRequestedEventArgs.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ShutdownRequestedEventArgs.cs @@ -4,6 +4,9 @@ namespace Avalonia.Controls.ApplicationLifetimes { public class ShutdownRequestedEventArgs : CancelEventArgs { - + /// + /// Is the operating system shutting down + /// + internal bool IsOSShutdown { get; init; } } } diff --git a/src/Avalonia.X11/X11PlatformLifetimeEvents.cs b/src/Avalonia.X11/X11PlatformLifetimeEvents.cs index 84b790ec2e..b6db27d6e0 100644 --- a/src/Avalonia.X11/X11PlatformLifetimeEvents.cs +++ b/src/Avalonia.X11/X11PlatformLifetimeEvents.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text; using System.Collections.Concurrent; using System.Runtime.InteropServices; @@ -229,7 +229,10 @@ namespace Avalonia.X11 { if (state is IntPtr smcConn) { - var e = new ShutdownRequestedEventArgs(); + var e = new ShutdownRequestedEventArgs() + { + IsOSShutdown = true, + }; if (_platform.Options.EnableSessionManagement) { diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index e9df0d04cc..79a03bbe23 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -148,11 +148,22 @@ namespace Avalonia.Win32 { if (ShutdownRequested != null) { - var e = new ShutdownRequestedEventArgs(); + // https://learn.microsoft.com/en-us/windows/win32/shutdown/wm-queryendsession + // > LPARAM lParam // logoff option + // > + // > This parameter can be one or more of the following values. If this parameter is 0, the system is shutting down or restarting (it is not possible to determine which event is occurring). + // > + // > - ENDSESSION_CLOSEAPP 0x00000001 The application is using a file that must be replaced, the system is being serviced, or system resources are exhausted. For more information, see Guidelines for Applications. + // > - ENDSESSION_CRITICAL 0x40000000 The application is forced to shut down. + // > - ENDSESSION_LOGOFF 0x80000000 The user is logging off. + var e = new ShutdownRequestedEventArgs() + { + IsOSShutdown = lParam == IntPtr.Zero, + }; ShutdownRequested(this, e); - if(e.Cancel) + if (e.Cancel) { return IntPtr.Zero; }