From d06464df61fced2d45d4192bf13962dd88fc7043 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 Apr 2022 16:15:08 +0100 Subject: [PATCH] nullable enable in avalonianative window / windowbase managed side. --- src/Avalonia.Native/AvaloniaNativePlatform.cs | 39 +++--- src/Avalonia.Native/WindowImpl.cs | 27 ++--- src/Avalonia.Native/WindowImplBase.cs | 114 ++++++++++-------- 3 files changed, 102 insertions(+), 78 deletions(-) diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index d1f28b720e..d64fde8e17 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -9,13 +9,15 @@ using Avalonia.OpenGL; using Avalonia.Platform; using Avalonia.Rendering; +#nullable enable + namespace Avalonia.Native { class AvaloniaNativePlatform : IPlatformSettings, IWindowingPlatform { private readonly IAvaloniaNativeFactory _factory; private AvaloniaNativePlatformOptions _options; - private AvaloniaNativePlatformOpenGlInterface _platformGl; + private AvaloniaNativePlatformOpenGlInterface? _platformGl; [DllImport("libAvaloniaNative")] static extern IntPtr CreateAvaloniaNative(); @@ -28,8 +30,8 @@ namespace Avalonia.Native public static AvaloniaNativePlatform Initialize(IntPtr factory, AvaloniaNativePlatformOptions options) { - var result = new AvaloniaNativePlatform(MicroComRuntime.CreateProxyFor(factory, true)); - result.DoInitialize(options); + var result = new AvaloniaNativePlatform(MicroComRuntime.CreateProxyFor(factory, true), options); + result.DoInitialize(); return result; } @@ -62,15 +64,20 @@ namespace Avalonia.Native public void SetupApplicationName () { - if(!string.IsNullOrWhiteSpace(Application.Current.Name)) + if(!string.IsNullOrWhiteSpace(Application.Current?.Name)) + { + _factory.MacOptions.SetApplicationTitle(Application.Current?.Name); + } + else { - _factory.MacOptions.SetApplicationTitle(Application.Current.Name); + _factory.MacOptions.SetApplicationTitle(""); } } - private AvaloniaNativePlatform(IAvaloniaNativeFactory factory) + private AvaloniaNativePlatform(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions options) { _factory = factory; + _options = options; } class GCHandleDeallocator : CallbackBase, IAvnGCHandleDeallocatorCallback @@ -81,10 +88,8 @@ namespace Avalonia.Native } } - void DoInitialize(AvaloniaNativePlatformOptions options) + void DoInitialize() { - _options = options; - var applicationPlatform = new AvaloniaNativeApplicationPlatform(); _factory.Initialize(new GCHandleDeallocator(), applicationPlatform); @@ -114,11 +119,17 @@ namespace Avalonia.Native .Bind().ToConstant(new MacOSNativeMenuCommands(_factory.CreateApplicationCommands())); var hotkeys = AvaloniaLocator.Current.GetService(); - hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers)); - hotkeys.MoveCursorToTheStartOfLineWithSelection.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); - hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers)); - hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); - + + if (hotkeys != null) + { + hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers)); + hotkeys.MoveCursorToTheStartOfLineWithSelection.Add(new KeyGesture(Key.Left, + hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); + hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers)); + hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, + hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); + } + if (_options.UseGpu) { try diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 865aab3fd1..0bae0730b3 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -1,13 +1,12 @@ using System; -using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Native.Interop; -using Avalonia.OpenGL; using Avalonia.Platform; -using Avalonia.Platform.Interop; + +#nullable enable namespace Avalonia.Native { @@ -15,14 +14,14 @@ namespace Avalonia.Native { private readonly IAvaloniaNativeFactory _factory; private readonly AvaloniaNativePlatformOptions _opts; - private readonly AvaloniaNativePlatformOpenGlInterface _glFeature; + private readonly AvaloniaNativePlatformOpenGlInterface? _glFeature; IAvnWindow _native; private double _extendTitleBarHeight = -1; private DoubleClickHelper _doubleClickHelper; internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts, - AvaloniaNativePlatformOpenGlInterface glFeature) : base(opts, glFeature) + AvaloniaNativePlatformOpenGlInterface? glFeature) : base(opts, glFeature) { _factory = factory; _opts = opts; @@ -82,12 +81,12 @@ namespace Avalonia.Native _native.SetDecorations((Interop.SystemDecorations)enabled); } - public void SetTitleBarColor(Avalonia.Media.Color color) + public void SetTitleBarColor(Media.Color color) { _native.SetTitleBarColor(new AvnColor { Alpha = color.A, Red = color.R, Green = color.G, Blue = color.B }); } - public void SetTitle(string title) + public void SetTitle(string? title) { _native.SetTitle(title ?? ""); } @@ -98,9 +97,9 @@ namespace Avalonia.Native set => _native.SetWindowState((AvnWindowState)value); } - public Action WindowStateChanged { get; set; } + public Action? WindowStateChanged { get; set; } - public Action ExtendClientAreaToDecorationsChanged { get; set; } + public Action? ExtendClientAreaToDecorationsChanged { get; set; } public Thickness ExtendedMargins { get; private set; } @@ -113,9 +112,9 @@ namespace Avalonia.Native { if(_isExtended) { - if(e.Type == RawPointerEventType.LeftButtonDown) + if(e.Type == RawPointerEventType.LeftButtonDown && _inputRoot is Window window) { - var visual = (_inputRoot as Window).Renderer.HitTestFirst(e.Position, _inputRoot as Window, x => + var visual = window.Renderer.HitTestFirst(e.Position, _inputRoot as Window, x => { if (x is IInputElement ie && (!ie.IsHitTestVisible || !ie.IsVisible)) { @@ -203,16 +202,16 @@ namespace Avalonia.Native // NO OP on OSX } - public Func Closing { get; set; } + public Func? Closing { get; set; } public ITopLevelNativeMenuExporter NativeMenuExporter { get; } public void Move(PixelPoint point) => Position = point; - public override IPopupImpl CreatePopup() => + public override IPopupImpl? CreatePopup() => _opts.OverlayPopups ? null : new PopupImpl(_factory, _opts, _glFeature, this); - public Action GotInputWhenDisabled { get; set; } + public Action? GotInputWhenDisabled { get; set; } public void SetParent(IWindowImpl parent) { diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 87b7a7608e..b83176e7e7 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -13,11 +13,13 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; +#nullable enable + namespace Avalonia.Native { internal class MacOSTopLevelWindowHandle : IPlatformHandle, IMacOSTopLevelPlatformHandle { - IAvnWindowBase _native; + private readonly IAvnWindowBase _native; public MacOSTopLevelWindowHandle(IAvnWindowBase native) { @@ -28,50 +30,55 @@ namespace Avalonia.Native public string HandleDescriptor => "NSWindow"; - public IntPtr NSView => _native?.ObtainNSViewHandle() ?? IntPtr.Zero; + public IntPtr NSView => _native.ObtainNSViewHandle(); - public IntPtr NSWindow => _native?.ObtainNSWindowHandle() ?? IntPtr.Zero; + public IntPtr NSWindow => _native.ObtainNSWindowHandle(); public IntPtr GetNSViewRetained() { - return _native?.ObtainNSViewHandleRetained() ?? IntPtr.Zero; + return _native.ObtainNSViewHandleRetained(); } public IntPtr GetNSWindowRetained() { - return _native?.ObtainNSWindowHandleRetained() ?? IntPtr.Zero; + return _native.ObtainNSWindowHandleRetained(); } } internal abstract class WindowBaseImpl : IWindowBaseImpl, IFramebufferPlatformSurface, ITopLevelImplWithNativeControlHost { - protected IInputRoot _inputRoot; - IAvnWindowBase _native; - private object _syncRoot = new object(); - private bool _deferredRendering = false; - private bool _gpu = false; + protected IInputRoot? _inputRoot; + IAvnWindowBase? _native; + private object _syncRoot = new(); + private bool _deferredRendering; + private bool _gpu; private readonly MouseDevice _mouse; private readonly IKeyboardDevice _keyboard; private readonly ICursorFactory _cursorFactory; private Size _savedLogicalSize; - private Size _lastRenderedLogicalSize; private double _savedScaling; - private GlPlatformSurface _glSurface; - private NativeControlHostImpl _nativeControlHost; - private IGlContext _glContext; + private GlPlatformSurface? _glSurface; + private NativeControlHostImpl? _nativeControlHost; + private IGlContext? _glContext; - internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, AvaloniaNativePlatformOpenGlInterface glFeature) + internal WindowBaseImpl(AvaloniaNativePlatformOptions opts, AvaloniaNativePlatformOpenGlInterface? glFeature) { _gpu = opts.UseGpu && glFeature != null; _deferredRendering = opts.UseDeferredRendering; - _keyboard = AvaloniaLocator.Current.GetService(); + var keyboardDevice = AvaloniaLocator.Current.GetService(); + + _keyboard = keyboardDevice ?? throw new Exception("Invalid configuration, missing IKeyboardDevice"); + _mouse = new MouseDevice(); - _cursorFactory = AvaloniaLocator.Current.GetService(); + + var cursorFactory = AvaloniaLocator.Current.GetService(); + + _cursorFactory = cursorFactory ?? throw new Exception("Invalid configuration, missing ICursorFactory"); } - protected void Init(IAvnWindowBase window, IAvnScreens screens, IGlContext glContext) + protected void Init(IAvnWindowBase window, IAvnScreens screens, IGlContext? glContext) { _native = window; _glContext = glContext; @@ -85,7 +92,7 @@ namespace Avalonia.Native _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) - .FirstOrDefault(m => m.Bounds.Contains(Position)); + .First(m => m.Bounds.Contains(Position)); Resize(new Size(monitor.WorkingArea.Width * 0.75d, monitor.WorkingArea.Height * 0.7d), PlatformResizeReason.Layout); } @@ -137,19 +144,18 @@ namespace Avalonia.Native if (_native == null) return false; cb(_native); - _lastRenderedLogicalSize = _savedLogicalSize; return true; } }, (int)w, (int)h, new Vector(dpi, dpi)); } - public Action LostFocus { get; set; } + public Action? LostFocus { get; set; } - public Action Paint { get; set; } - public Action Resized { get; set; } - public Action Closed { get; set; } + public Action? Paint { get; set; } + public Action? Resized { get; set; } + public Action? Closed { get; set; } public IMouseDevice MouseDevice => _mouse; - public abstract IPopupImpl CreatePopup(); + public abstract IPopupImpl? CreatePopup(); protected unsafe class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents { @@ -165,12 +171,12 @@ namespace Avalonia.Native var n = _parent._native; try { - _parent?.Closed?.Invoke(); + _parent.Closed?.Invoke(); } finally { - _parent?.Dispose(); + _parent.Dispose(); n?.Dispose(); } } @@ -188,7 +194,7 @@ namespace Avalonia.Native void IAvnWindowBaseEvents.Resized(AvnSize* size, AvnPlatformResizeReason reason) { - if (_parent?._native != null) + if (_parent._native != null) { var s = new Size(size->Width, size->Height); _parent._savedLogicalSize = s; @@ -240,21 +246,26 @@ namespace Avalonia.Native { var device = AvaloniaLocator.Current.GetService(); - IDataObject dataObject = null; - if (dataObjectHandle != IntPtr.Zero) - dataObject = GCHandle.FromIntPtr(dataObjectHandle).Target as IDataObject; - - using(var clipboardDataObject = new ClipboardDataObject(clipboard)) + if (device != null && _parent._inputRoot != null) { - if (dataObject == null) - dataObject = clipboardDataObject; - - var args = new RawDragEvent(device, (RawDragEventType)type, - _parent._inputRoot, position.ToAvaloniaPoint(), dataObject, (DragDropEffects)effects, - (RawInputModifiers)modifiers); - _parent.Input(args); - return (AvnDragDropEffects)args.Effects; + IDataObject? dataObject = null; + if (dataObjectHandle != IntPtr.Zero) + dataObject = GCHandle.FromIntPtr(dataObjectHandle).Target as IDataObject; + + using (var clipboardDataObject = new ClipboardDataObject(clipboard)) + { + if (dataObject == null) + dataObject = clipboardDataObject; + + var args = new RawDragEvent(device, (RawDragEventType)type, + _parent._inputRoot, position.ToAvaloniaPoint(), dataObject, (DragDropEffects)effects, + (RawInputModifiers)modifiers); + _parent.Input?.Invoke(args); + return (AvnDragDropEffects)args.Effects; + } } + + return AvnDragDropEffects.None; } } @@ -263,6 +274,7 @@ namespace Avalonia.Native _native?.Activate(); } + public bool RawTextInputEvent(uint timeStamp, string text) { if (_inputRoot is null) @@ -409,8 +421,8 @@ namespace Avalonia.Native public double DesktopScaling => 1; - public Action Deactivated { get; set; } - public Action Activated { get; set; } + public Action? Deactivated { get; set; } + public Action? Activated { get; set; } public void SetCursor(ICursorImpl cursor) { @@ -420,19 +432,21 @@ namespace Avalonia.Native } var newCursor = cursor as AvaloniaNativeCursor; - newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor); - _native.SetCursor(newCursor.Cursor); + + newCursor ??= (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor); + + _native.SetCursor(newCursor?.Cursor); } - public Action PositionChanged { get; set; } + public Action? PositionChanged { get; set; } - public Action Input { get; set; } + public Action? Input { get; set; } - public Action ScalingChanged { get; set; } + public Action? ScalingChanged { get; set; } - public Action TransparencyLevelChanged { get; set; } + public Action? TransparencyLevelChanged { get; set; } - public IScreenImpl Screen { get; private set; } + public IScreenImpl? Screen { get; private set; } // TODO