From 2273534a57821b5fe39b374e7610e518e624a0be Mon Sep 17 00:00:00 2001 From: Stan Wijckmans Date: Mon, 5 Sep 2022 22:15:39 +0200 Subject: [PATCH 1/4] Add API to prevent App Nap. --- .../project.pbxproj | 4 ++ .../src/OSX/PlatformBehaviorInhibition.mm | 39 +++++++++++++++++++ native/Avalonia.Native/src/OSX/common.h | 1 + native/Avalonia.Native/src/OSX/main.mm | 11 ++++++ .../Platform/IPlatformBehaviorInhibition.cs | 12 ++++++ .../PlatformInhibitionType.cs | 13 +++++++ src/Avalonia.Controls/TopLevel.cs | 25 ++++++++++++ src/Avalonia.Native/AvaloniaNativePlatform.cs | 21 ---------- .../PlatformBehaviorInhibition.cs | 20 ++++++++++ src/Avalonia.Native/avn.idl | 7 ++++ 10 files changed, 132 insertions(+), 21 deletions(-) create mode 100644 native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm create mode 100644 src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs create mode 100644 src/Avalonia.Controls/PlatformInhibitionType.cs create mode 100644 src/Avalonia.Native/PlatformBehaviorInhibition.cs diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj index 41d1534f8d..c49290314d 100644 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 523484CA26EA688F00EA0C2C /* trayicon.mm in Sources */ = {isa = PBXBuildFile; fileRef = 523484C926EA688F00EA0C2C /* trayicon.mm */; }; 5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; }; 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; }; + 855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */; }; AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; }; AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB1E522B217613570091CD71 /* OpenGL.framework */; }; AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; }; @@ -95,6 +96,7 @@ 5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = ""; }; 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = ""; }; 5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = ""; }; + 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformBehaviorInhibition.mm; sourceTree = ""; }; AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; AB1E522B217613570091CD71 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -140,6 +142,7 @@ AB7A61E62147C814003C5833 = { isa = PBXGroup; children = ( + 855EDC9E28C6546F00807998 /* PlatformBehaviorInhibition.mm */, BC11A5BC2608D58F0017BAD0 /* automation.h */, BC11A5BD2608D58F0017BAD0 /* automation.mm */, 1A1852DB23E05814008F0DED /* deadlock.mm */, @@ -288,6 +291,7 @@ 1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */, BC11A5BF2608D58F0017BAD0 /* automation.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, + 855EDC9F28C6546F00807998 /* PlatformBehaviorInhibition.mm in Sources */, 520624B322973F4100C4DCEF /* menu.mm in Sources */, 37A517B32159597E00FBA241 /* Screens.mm in Sources */, 1AFD334123E03C4F0042899B /* controlhost.mm in Sources */, diff --git a/native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm b/native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm new file mode 100644 index 0000000000..db054d82ef --- /dev/null +++ b/native/Avalonia.Native/src/OSX/PlatformBehaviorInhibition.mm @@ -0,0 +1,39 @@ +#include "common.h" + +namespace +{ + id s_inhibitAppSleepHandle{}; +} + +class PlatformBehaviorInhibition : public ComSingleObject +{ +public: + FORWARD_IUNKNOWN() + + virtual void SetInhibitAppSleep(bool inhibitAppSleep, char* reason) override + { + START_COM_CALL; + + @autoreleasepool + { + if (inhibitAppSleep && s_inhibitAppSleepHandle == nullptr) + { + NSActivityOptions options = NSActivityUserInitiatedAllowingIdleSystemSleep; + s_inhibitAppSleepHandle = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:[NSString stringWithUTF8String: reason]]; + } + + if (!inhibitAppSleep) + { + s_inhibitAppSleepHandle = nullptr; + } + } + } +}; + +extern IAvnPlatformBehaviorInhibition* CreatePlatformBehaviorInhibition() +{ + @autoreleasepool + { + return new PlatformBehaviorInhibition(); + } +} diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h index 972927b99d..4353737dc8 100644 --- a/native/Avalonia.Native/src/OSX/common.h +++ b/native/Avalonia.Native/src/OSX/common.h @@ -26,6 +26,7 @@ extern IAvnTrayIcon* CreateTrayIcon(); extern IAvnMenuItem* CreateAppMenuItem(); extern IAvnMenuItem* CreateAppMenuItemSeparator(); extern IAvnApplicationCommands* CreateApplicationCommands(); +extern IAvnPlatformBehaviorInhibition* CreatePlatformBehaviorInhibition(); extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent); extern IAvnPlatformSettings* CreatePlatformSettings(); extern void SetAppMenu(IAvnMenu *menu); diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm index 99063e600e..4bfda4b531 100644 --- a/native/Avalonia.Native/src/OSX/main.mm +++ b/native/Avalonia.Native/src/OSX/main.mm @@ -408,6 +408,17 @@ public: return S_OK; } } + + virtual HRESULT CreatePlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition** ppv) override + { + START_COM_CALL; + + @autoreleasepool + { + *ppv = ::CreatePlatformBehaviorInhibition(); + return S_OK; + } + } }; extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative() diff --git a/src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs b/src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs new file mode 100644 index 0000000000..227e65c08d --- /dev/null +++ b/src/Avalonia.Base/Platform/IPlatformBehaviorInhibition.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; + +namespace Avalonia.Platform +{ + /// + /// Allows to inhibit platform specific behavior. + /// + public interface IPlatformBehaviorInhibition + { + Task SetInhibitAppSleep(bool inhibitAppSleep, string reason); + } +} diff --git a/src/Avalonia.Controls/PlatformInhibitionType.cs b/src/Avalonia.Controls/PlatformInhibitionType.cs new file mode 100644 index 0000000000..03e3270e0b --- /dev/null +++ b/src/Avalonia.Controls/PlatformInhibitionType.cs @@ -0,0 +1,13 @@ +namespace Avalonia.Controls +{ + /// + /// A platform specific behavior that can be inhibited. + /// + public enum PlatformInhibitionType + { + /// + /// When inhibited, prevents the app from being put to sleep or being given a lower priority when not in focus. + /// + AppSleep + } +} diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index f956fb8724..ed11dec1d0 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -20,6 +20,7 @@ using Avalonia.Styling; using Avalonia.Utilities; using Avalonia.Input.Platform; using System.Linq; +using System.Threading.Tasks; namespace Avalonia.Controls { @@ -570,6 +571,30 @@ namespace Avalonia.Controls /// The event args. protected virtual void OnClosed(EventArgs e) => Closed?.Invoke(this, e); + /// + /// Requests a to be inhibited. + /// The behavior remains inhibited until the return value is disposed. + /// The available set of s depends on the platform. + /// If a behavior is inhibited on a platform where this type is not supported the request will have no effect. + /// + protected async Task RequestPlatformInhibition(PlatformInhibitionType type, string reason) + { + var platformBehaviorInhibition = PlatformImpl?.TryGetFeature(); + if (platformBehaviorInhibition == null) + { + return Disposable.Create(() => { }); + } + + switch (type) + { + case PlatformInhibitionType.AppSleep: + await platformBehaviorInhibition.SetInhibitAppSleep(true, reason); + return Disposable.Create(() => platformBehaviorInhibition.SetInhibitAppSleep(false, reason).Wait()); + default: + return Disposable.Create(() => { }); + } + } + /// /// Tries to get a service from an , logging a /// warning if not found. diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index 09feb0c768..67b55bd512 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -158,25 +158,4 @@ namespace Avalonia.Native throw new NotImplementedException(); } } - - public class AvaloniaNativeMacOptions - { - private readonly IAvnMacOptions _opts; - private bool _showInDock; - internal AvaloniaNativeMacOptions(IAvnMacOptions opts) - { - _opts = opts; - ShowInDock = true; - } - - public bool ShowInDock - { - get => _showInDock; - set - { - _showInDock = value; - _opts.SetShowInDock(value ? 1 : 0); - } - } - } } diff --git a/src/Avalonia.Native/PlatformBehaviorInhibition.cs b/src/Avalonia.Native/PlatformBehaviorInhibition.cs new file mode 100644 index 0000000000..dfbfe8a5e5 --- /dev/null +++ b/src/Avalonia.Native/PlatformBehaviorInhibition.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Avalonia.Native.Interop; +using Avalonia.Platform; + +namespace Avalonia.Native +{ + internal class PlatformBehaviorInhibition : IPlatformBehaviorInhibition + { + readonly IAvnPlatformBehaviorInhibition _native; + + internal PlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition native) + => _native = native; + + public Task SetInhibitAppSleep(bool inhibitAppSleep, string reason) + { + _native.SetInhibitAppSleep(inhibitAppSleep ? 1 : 0, reason); + return Task.CompletedTask; + } + } +} diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl index a062fdc61d..db78873672 100644 --- a/src/Avalonia.Native/avn.idl +++ b/src/Avalonia.Native/avn.idl @@ -503,6 +503,7 @@ interface IAvaloniaNativeFactory : IUnknown HRESULT CreateTrayIcon(IAvnTrayIcon** ppv); HRESULT CreateApplicationCommands(IAvnApplicationCommands** ppv); HRESULT CreatePlatformSettings(IAvnPlatformSettings** ppv); + HRESULT CreatePlatformBehaviorInhibition(IAvnPlatformBehaviorInhibition** ppv); } [uuid(233e094f-9b9f-44a3-9a6e-6948bbdd9fb1)] @@ -924,3 +925,9 @@ interface IAvnPlatformSettings : IUnknown uint GetAccentColor(); void RegisterColorsChange(IAvnActionCallback* callback); } + +[uuid(12edf00d-5803-4d3f-9947-b4840e5e9372)] +interface IAvnPlatformBehaviorInhibition : IUnknown +{ + void SetInhibitAppSleep(bool inhibitAppSleep, char* reason); +} From f4e35493c9176edc146fcd2b73033a6e0363b7b9 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 12 Feb 2023 10:52:51 -0500 Subject: [PATCH 2/4] Add missed IPlatformBehaviorInhibition to the TryGetFeature --- src/Avalonia.Native/WindowImplBase.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 50bee0d395..4357f3b705 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -63,6 +63,7 @@ namespace Avalonia.Native private GlPlatformSurface _glSurface; private NativeControlHostImpl _nativeControlHost; private IStorageProvider _storageProvider; + private PlatformBehaviorInhibition _platformBehaviorInhibition; internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts, AvaloniaNativeGlPlatformGraphics glFeature) @@ -88,6 +89,7 @@ namespace Avalonia.Native _savedScaling = RenderScaling; _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); _storageProvider = new SystemDialogs(this, _factory.CreateSystemDialogs()); + _platformBehaviorInhibition = new PlatformBehaviorInhibition(_factory.CreatePlatformBehaviorInhibition()); var monitor = Screen.AllScreens.OrderBy(x => x.Scaling) .FirstOrDefault(m => m.Bounds.Contains(Position)); @@ -521,6 +523,11 @@ namespace Avalonia.Native return _storageProvider; } + if (featureType == typeof(IPlatformBehaviorInhibition)) + { + return _platformBehaviorInhibition; + } + return null; } From 814ae8401117e5549100cb96058124c5438ceb2f Mon Sep 17 00:00:00 2001 From: Mike James Date: Mon, 13 Feb 2023 13:57:43 +0100 Subject: [PATCH 3/4] Updated readme to include XPF banner --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index c2be487af3..2600cf83cc 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,5 @@ +[![GH_Banner](https://user-images.githubusercontent.com/552074/218457976-92e76834-9e22-4e35-acfa-aa50281bc0f9.png)](https://avaloniaui.net/xpf) + [![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
From 3f3eff6563bd78a4dca3cb6bbec7ed991b86aa92 Mon Sep 17 00:00:00 2001 From: "jc.yuan" Date: Mon, 13 Feb 2023 23:10:15 +0800 Subject: [PATCH 4/4] remove the duplicated line --- src/Windows/Avalonia.Win32/Win32GlManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs index ab6de1a027..6c446fed6a 100644 --- a/src/Windows/Avalonia.Win32/Win32GlManager.cs +++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs @@ -16,7 +16,6 @@ namespace Avalonia.Win32 { var gl = InitializeCore(); AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); - AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); return gl; }