diff --git a/src/Avalonia.Controls/Platform/IPopupImpl.cs b/src/Avalonia.Controls/Platform/IPopupImpl.cs index cd86045dee..320130bc91 100644 --- a/src/Avalonia.Controls/Platform/IPopupImpl.cs +++ b/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); } diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs index b3436d4176..952ba92e9b 100644 --- a/src/Avalonia.Controls/Primitives/PopupRoot.cs +++ b/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, diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 6634ab4d7b..22748f6aa3 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/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(null), + () => _platform.Options.UseDBusFilePicker ? DBusSystemDialog.TryCreateAsync(Handle) : Task.FromResult(null), () => GtkSystemDialog.TryCreate(this) }); } @@ -351,17 +354,17 @@ namespace Avalonia.X11 public double DesktopScaling => RenderScaling; public IEnumerable Surfaces { get; } - public Action Input { get; set; } - public Action Paint { get; set; } - public Action Resized { get; set; } + public Action? Input { get; set; } + public Action? Paint { get; set; } + public Action? Resized { get; set; } //TODO - public Action ScalingChanged { get; set; } - public Action Deactivated { get; set; } - public Action Activated { get; set; } - public Func Closing { get; set; } - public Action WindowStateChanged { get; set; } + public Action? ScalingChanged { get; set; } + public Action? Deactivated { get; set; } + public Action? Activated { get; set; } + public Func? Closing { get; set; } + public Action? WindowStateChanged { get; set; } - public Action TransparencyLevelChanged + public Action? TransparencyLevelChanged { get => _transparencyHelper?.TransparencyLevelChanged; set @@ -371,7 +374,7 @@ namespace Avalonia.X11 } } - public Action ExtendClientAreaToDecorationsChanged { get; set; } + public Action? 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 PositionChanged { get; set; } - public Action LostFocus { get; set; } + public Action? Closed { get; set; } + public Action? 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);