Browse Source

Merge pull request #10600 from AvaloniaUI/fixes/x11window-nre

Add nullable reference checking to X11Window.
Max Katz 2 years ago
parent
commit
68d680c5cd

+ 1 - 1
src/Avalonia.Controls/Platform/IPopupImpl.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Platform
     [Unstable]
     public interface IPopupImpl : IWindowBaseImpl
     {
-        IPopupPositioner PopupPositioner { get; }
+        IPopupPositioner? PopupPositioner { get; }
 
         void SetWindowManagerAddShadowHint(bool enabled);
     }

+ 1 - 1
src/Avalonia.Controls/Primitives/PopupRoot.cs

@@ -95,7 +95,7 @@ namespace Avalonia.Controls.Primitives
 
         private void UpdatePosition()
         {
-            PlatformImpl?.PopupPositioner.Update(_positionerParameters);
+            PlatformImpl?.PopupPositioner?.Update(_positionerParameters);
         }
 
         public void ConfigurePosition(Visual target, PlacementMode placement, Point offset,

+ 44 - 32
src/Avalonia.X11/X11Window.cs

@@ -25,6 +25,9 @@ using Avalonia.X11.NativeDialogs;
 using static Avalonia.X11.XLib;
 // ReSharper disable IdentifierTypo
 // ReSharper disable StringLiteralTypo
+
+#nullable enable
+
 namespace Avalonia.X11
 {
     internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
@@ -35,11 +38,11 @@ namespace Avalonia.X11
         private XConfigureEvent? _configure;
         private PixelPoint? _configurePoint;
         private bool _triggeredExpose;
-        private IInputRoot _inputRoot;
+        private IInputRoot? _inputRoot;
         private readonly MouseDevice _mouse;
         private readonly TouchDevice _touch;
         private readonly IKeyboardDevice _keyboard;
-        private readonly ITopLevelNativeMenuExporter _nativeMenuExporter;
+        private readonly ITopLevelNativeMenuExporter? _nativeMenuExporter;
         private readonly IStorageProvider _storageProvider;
         private readonly X11NativeControlHost _nativeControlHost;
         private PixelPoint? _position;
@@ -54,8 +57,8 @@ namespace Avalonia.X11
         private bool _wasMappedAtLeastOnce = false;
         private double? _scalingOverride;
         private bool _disabled;
-        private TransparencyHelper _transparencyHelper;
-        private RawEventGrouper _rawEventGrouper;
+        private TransparencyHelper? _transparencyHelper;
+        private RawEventGrouper? _rawEventGrouper;
         private bool _useRenderWindow = false;
         private bool _usePositioningFlags = false;
 
@@ -66,7 +69,7 @@ namespace Avalonia.X11
             WaitPaint
         }
         
-        public X11Window(AvaloniaX11Platform platform, IWindowImpl popupParent)
+        public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent)
         {
             _platform = platform;
             _popup = popupParent != null;
@@ -196,7 +199,7 @@ namespace Avalonia.X11
 
             XFlush(_x11.Display);
             if(_popup)
-                PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(popupParent, MoveResize));
+                PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(popupParent!, MoveResize));
             if (platform.Options.UseDBusMenu)
                 _nativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle);
             _nativeControlHost = new X11NativeControlHost(_platform, this);
@@ -214,7 +217,7 @@ namespace Avalonia.X11
 
             _storageProvider = new CompositeStorageProvider(new[]
             {
-                () => _platform.Options.UseDBusFilePicker ? DBusSystemDialog.TryCreateAsync(Handle) : Task.FromResult<IStorageProvider>(null),
+                () => _platform.Options.UseDBusFilePicker ? DBusSystemDialog.TryCreateAsync(Handle) : Task.FromResult<IStorageProvider?>(null),
                 () => GtkSystemDialog.TryCreate(this)
             });
         }
@@ -351,17 +354,17 @@ namespace Avalonia.X11
         public double DesktopScaling => RenderScaling;
 
         public IEnumerable<object> Surfaces { get; }
-        public Action<RawInputEventArgs> Input { get; set; }
-        public Action<Rect> Paint { get; set; }
-        public Action<Size, PlatformResizeReason> Resized { get; set; }
+        public Action<RawInputEventArgs>? Input { get; set; }
+        public Action<Rect>? Paint { get; set; }
+        public Action<Size, PlatformResizeReason>? Resized { get; set; }
         //TODO
-        public Action<double> ScalingChanged { get; set; }
-        public Action Deactivated { get; set; }
-        public Action Activated { get; set; }
-        public Func<WindowCloseReason, bool> Closing { get; set; }
-        public Action<WindowState> WindowStateChanged { get; set; }
+        public Action<double>? ScalingChanged { get; set; }
+        public Action? Deactivated { get; set; }
+        public Action? Activated { get; set; }
+        public Func<WindowCloseReason, bool>? Closing { get; set; }
+        public Action<WindowState>? WindowStateChanged { get; set; }
 
-        public Action<WindowTransparencyLevel> TransparencyLevelChanged
+        public Action<WindowTransparencyLevel>? TransparencyLevelChanged
         {
             get => _transparencyHelper?.TransparencyLevelChanged;
             set
@@ -371,7 +374,7 @@ namespace Avalonia.X11
             }
         }
 
-        public Action<bool> ExtendClientAreaToDecorationsChanged { get; set; }
+        public Action<bool>? ExtendClientAreaToDecorationsChanged { get; set; }
 
         public Thickness ExtendedMargins { get; } = new Thickness();
 
@@ -379,15 +382,18 @@ namespace Avalonia.X11
 
         public bool IsClientAreaExtendedToDecorations { get; }
 
-        public Action Closed { get; set; }
-        public Action<PixelPoint> PositionChanged { get; set; }
-        public Action LostFocus { get; set; }
+        public Action? Closed { get; set; }
+        public Action<PixelPoint>? PositionChanged { get; set; }
+        public Action? LostFocus { get; set; }
 
         public IRenderer CreateRenderer(IRenderRoot root) =>
             new CompositingRenderer(root, _platform.Compositor, () => Surfaces);
 
         private void OnEvent(ref XEvent ev)
         {
+            if (_inputRoot is null)
+                return;
+
             if (ev.type == XEventName.MapNotify)
             {
                 _mapped = true;
@@ -434,7 +440,8 @@ namespace Avalonia.X11
                             2 => RawPointerEventType.MiddleButtonDown,
                             3 => RawPointerEventType.RightButtonDown,
                             8 => RawPointerEventType.XButton1Down,
-                            9 => RawPointerEventType.XButton2Down
+                            9 => RawPointerEventType.XButton2Down,
+                            _ => throw new NotSupportedException("Unexepected RawPointerEventType.")
                         },
                         ref ev, ev.ButtonEvent.state);
                 else
@@ -462,7 +469,8 @@ namespace Avalonia.X11
                             2 => RawPointerEventType.MiddleButtonUp,
                             3 => RawPointerEventType.RightButtonUp,
                             8 => RawPointerEventType.XButton1Up,
-                            9 => RawPointerEventType.XButton2Up
+                            9 => RawPointerEventType.XButton2Up,
+                            _ => throw new NotSupportedException("Unexepected RawPointerEventType.")
                         },
                         ref ev, ev.ButtonEvent.state);
             }
@@ -618,7 +626,7 @@ namespace Avalonia.X11
             {
                 // Occurs once the window has been mapped, which is the earliest the extents
                 // can be retrieved, so invoke event to force update of TopLevel.FrameSize.
-                Resized.Invoke(ClientSize, PlatformResizeReason.Unspecified);
+                Resized?.Invoke(ClientSize, PlatformResizeReason.Unspecified);
             }
 
             if (atom == _x11.Atoms._NET_WM_STATE)
@@ -712,6 +720,8 @@ namespace Avalonia.X11
 
         private void DispatchInput(RawInputEventArgs args)
         {
+            if (_inputRoot is null)
+                return;
             Input?.Invoke(args);
             if (!args.Handled && args is RawKeyEventArgsWithText text && !string.IsNullOrEmpty(text.Text))
                 Input?.Invoke(new RawTextInputEventArgs(_keyboard, args.Timestamp, _inputRoot, text.Text));
@@ -744,11 +754,13 @@ namespace Avalonia.X11
             if (args is RawDragEvent drag)
                 drag.Location = drag.Location / RenderScaling;
             
-            _rawEventGrouper.HandleEvent(args);
+            _rawEventGrouper?.HandleEvent(args);
         }
 
         private void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
         {
+            if (_inputRoot is null)
+                return;
             var mev = new RawPointerEventArgs(
                 _mouse, (ulong)ev.ButtonEvent.time.ToInt64(), _inputRoot,
                 type, new Point(ev.ButtonEvent.x, ev.ButtonEvent.y), TranslateModifiers(mods));
@@ -783,7 +795,7 @@ namespace Avalonia.X11
 
         }
 
-        public IInputRoot InputRoot => _inputRoot;
+        public IInputRoot? InputRoot => _inputRoot;
         
         public void SetInputRoot(IInputRoot inputRoot)
         {
@@ -795,7 +807,7 @@ namespace Avalonia.X11
             Cleanup();            
         }
 
-        public virtual object TryGetFeature(Type featureType)
+        public virtual object? TryGetFeature(Type featureType)
         {
             if (featureType == typeof(ITopLevelNativeMenuExporter))
             {
@@ -953,7 +965,7 @@ namespace Avalonia.X11
             UpdateSizeHints(null);
         }
 
-        public void SetCursor(ICursorImpl cursor)
+        public void SetCursor(ICursorImpl? cursor)
         {
             if (cursor == null)
                 XDefineCursor(_x11.Display, _handle, _x11.DefaultCursor);
@@ -996,7 +1008,7 @@ namespace Avalonia.X11
         public IMouseDevice MouseDevice => _mouse;
         public TouchDevice TouchDevice => _touch;
 
-        public IPopupImpl CreatePopup() 
+        public IPopupImpl? CreatePopup() 
             => _platform.Options.OverlayPopups ? null : new X11Window(_platform, this);
 
         public void Activate()
@@ -1082,7 +1094,7 @@ namespace Avalonia.X11
             BeginMoveResize(side, e);
         }
 
-        public void SetTitle(string title)
+        public void SetTitle(string? title)
         {
             if (string.IsNullOrEmpty(title))
             {
@@ -1161,9 +1173,9 @@ namespace Avalonia.X11
         {
         }
 
-        public Action GotInputWhenDisabled { get; set; }
+        public Action? GotInputWhenDisabled { get; set; }
 
-        public void SetIcon(IWindowIconImpl icon)
+        public void SetIcon(IWindowIconImpl? icon)
         {
             if (icon != null)
             {
@@ -1218,7 +1230,7 @@ namespace Avalonia.X11
             );
         }
 
-        public IPopupPositioner PopupPositioner { get; }
+        public IPopupPositioner? PopupPositioner { get; }
 
         public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) =>
             _transparencyHelper?.SetTransparencyRequest(transparencyLevel);