diff --git a/src/Avalonia.X11/Avalonia.X11.csproj b/src/Avalonia.X11/Avalonia.X11.csproj index b09bea889f0..606cdfd2514 100644 --- a/src/Avalonia.X11/Avalonia.X11.csproj +++ b/src/Avalonia.X11/Avalonia.X11.csproj @@ -13,6 +13,7 @@ + diff --git a/src/Avalonia.X11/Dispatching/GLibDispatcherImpl.cs b/src/Avalonia.X11/Dispatching/GLibDispatcherImpl.cs index bf5ffa370d1..1757b048776 100644 --- a/src/Avalonia.X11/Dispatching/GLibDispatcherImpl.cs +++ b/src/Avalonia.X11/Dispatching/GLibDispatcherImpl.cs @@ -1,4 +1,3 @@ -#nullable enable using System; using System.Collections.Generic; using System.Diagnostics; @@ -312,4 +311,4 @@ public void Dispose() } public X11EventDispatcher EventDispatcher => _x11Events; -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/Dispatching/X11PlatformThreading.cs b/src/Avalonia.X11/Dispatching/X11PlatformThreading.cs index 529e2cd8dc5..b071e405fdd 100644 --- a/src/Avalonia.X11/Dispatching/X11PlatformThreading.cs +++ b/src/Avalonia.X11/Dispatching/X11PlatformThreading.cs @@ -186,8 +186,8 @@ public void Signal() public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _mainThread; - public event Action Signaled; - public event Action Timer; + public event Action? Signaled; + public event Action? Timer; public void UpdateTimer(long? dueTimeInMs) { diff --git a/src/Avalonia.X11/Glx/Glx.cs b/src/Avalonia.X11/Glx/Glx.cs index fceea3718c0..c3b20ad00dc 100644 --- a/src/Avalonia.X11/Glx/Glx.cs +++ b/src/Avalonia.X11/Glx/Glx.cs @@ -115,6 +115,9 @@ public static IntPtr SafeGetProcAddress(string proc) public string[] GetExtensions(IntPtr display) { var s = Marshal.PtrToStringAnsi(QueryExtensionsString(display, 0)); + if (string.IsNullOrEmpty(s)) + return []; + return s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()).ToArray(); diff --git a/src/Avalonia.X11/Glx/GlxContext.cs b/src/Avalonia.X11/Glx/GlxContext.cs index 4801befbed3..94c15d9008d 100644 --- a/src/Avalonia.X11/Glx/GlxContext.cs +++ b/src/Avalonia.X11/Glx/GlxContext.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; using System.Collections.Generic; using System.Threading; diff --git a/src/Avalonia.X11/Glx/GlxDisplay.cs b/src/Avalonia.X11/Glx/GlxDisplay.cs index 9ce34ec7c41..0d766fee9c8 100644 --- a/src/Avalonia.X11/Glx/GlxDisplay.cs +++ b/src/Avalonia.X11/Glx/GlxDisplay.cs @@ -119,13 +119,13 @@ public GlxContext CreateContext() => CreateContext(CreatePBuffer(), null, Deferr public GlxContext CreateContext(IGlContext share) => CreateContext(CreatePBuffer(), share, share.SampleCount, share.StencilSize, true); - private GlxContext CreateContext(IntPtr defaultXid, IGlContext share, + private GlxContext CreateContext(IntPtr defaultXid, IGlContext? share, int sampleCount, int stencilSize, bool ownsPBuffer) { - var sharelist = ((GlxContext)share)?.Handle ?? IntPtr.Zero; + var sharelist = ((GlxContext?)share)?.Handle ?? IntPtr.Zero; IntPtr handle = default; - GlxContext Create(GlVersion profile) + GlxContext? Create(GlVersion profile) { var profileMask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; if (profile.Type == GlProfileType.OpenGL && @@ -149,7 +149,7 @@ GlxContext Create(GlVersion profile) if (handle != IntPtr.Zero) { _version = profile; - return new GlxContext(new GlxInterface(), handle, this, (GlxContext)share, profile, + return new GlxContext(new GlxInterface(), handle, this, (GlxContext?)share, profile, sampleCount, stencilSize, _x11, defaultXid, ownsPBuffer); } @@ -162,7 +162,7 @@ GlxContext Create(GlVersion profile) return null; } - GlxContext rv = null; + GlxContext? rv = null; if (_version.HasValue) { rv = Create(_version.Value); diff --git a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs index 0c7c7d21659..a4d6e274519 100644 --- a/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs +++ b/src/Avalonia.X11/Glx/GlxGlPlatformSurface.cs @@ -96,7 +96,7 @@ public void Dispose() public PixelSize Size => _size ?? _info.Size; public double Scaling => _info.Scaling; - public bool IsYFlipped { get; } + public bool IsYFlipped => false; } } } diff --git a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs index 58336522c1d..356121dc4bc 100644 --- a/src/Avalonia.X11/Glx/GlxPlatformFeature.cs +++ b/src/Avalonia.X11/Glx/GlxPlatformFeature.cs @@ -8,23 +8,25 @@ namespace Avalonia.X11.Glx { internal class GlxPlatformGraphics : IPlatformGraphics { - public GlxDisplay Display { get; private set; } + public GlxDisplay Display { get; } public bool CanCreateContexts => true; public bool CanShareContexts => true; public bool UsesSharedContext => false; IPlatformGraphicsContext IPlatformGraphics.CreateContext() => Display.CreateContext(); public IPlatformGraphicsContext GetSharedContext() => throw new NotSupportedException(); - - public static GlxPlatformGraphics TryCreate(X11Info x11, IList glProfiles) + + public GlxPlatformGraphics(GlxDisplay display) + { + Display = display; + } + + public static GlxPlatformGraphics? TryCreate(X11Info x11, IList glProfiles) { try { var disp = new GlxDisplay(x11, glProfiles); - return new GlxPlatformGraphics - { - Display = disp - }; + return new GlxPlatformGraphics(disp); } catch(Exception e) { diff --git a/src/Avalonia.X11/Interop/Glib.cs b/src/Avalonia.X11/Interop/Glib.cs index 543d2892dd6..84a15819250 100644 --- a/src/Avalonia.X11/Interop/Glib.cs +++ b/src/Avalonia.X11/Interop/Glib.cs @@ -1,9 +1,10 @@ #nullable enable + using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Avalonia.Platform.Interop; -using static Avalonia.X11.Interop.Glib; + namespace Avalonia.X11.Interop; internal static unsafe class Glib @@ -75,7 +76,7 @@ public static uint g_timeout_add_once(uint interval, Action cb) => private static readonly GDestroyNotify s_gcHandleDestroyNotify = handle => GCHandle.FromIntPtr(handle).Free(); private static readonly GSourceFunc s_sourceFuncDispatchCallback = - handle => ((Func)GCHandle.FromIntPtr(handle).Target)() ? 1 : 0; + handle => ((Func)GCHandle.FromIntPtr(handle).Target!)() ? 1 : 0; [DllImport(GlibName)] private static extern uint g_idle_add_full (int priority, GSourceFunc function, IntPtr data, GDestroyNotify notify); @@ -108,7 +109,7 @@ public enum GIOCondition public delegate int GUnixFDSourceFunc(int fd, GIOCondition condition, IntPtr user_data); private static readonly GUnixFDSourceFunc s_unixFdSourceCallback = (fd, cond, handle) => - ((Func)GCHandle.FromIntPtr(handle).Target)(fd, cond) ? 1 : 0; + ((Func)GCHandle.FromIntPtr(handle).Target!)(fd, cond) ? 1 : 0; [DllImport(GlibName)] public static extern uint g_unix_fd_add_full (int priority, @@ -152,6 +153,7 @@ public void Dispose() } public static IDisposable ConnectSignal(IntPtr obj, string name, T handler) + where T : notnull { var handle = GCHandle.Alloc(handler); var ptr = Marshal.GetFunctionPointerForDelegate(handler); @@ -187,4 +189,4 @@ internal unsafe struct GSList { public readonly IntPtr Data; public readonly GSList* Next; -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs index 97874d71f08..70010863bab 100644 --- a/src/Avalonia.X11/NativeDialogs/Gtk.cs +++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs @@ -1,10 +1,10 @@ +#nullable enable + using System; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Avalonia.Platform.Interop; -using Avalonia.Threading; -using Avalonia.X11.Dispatching; using Avalonia.X11.Interop; // ReSharper disable IdentifierTypo @@ -142,7 +142,7 @@ public static extern void public static IntPtr GetForeignWindow(IntPtr xid) => gdk_x11_window_foreign_new_for_display(s_display, xid); static object s_startGtkLock = new(); - static Task s_startGtkTask; + static Task? s_startGtkTask; public static Task StartGtk() { diff --git a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs index 5dfa9a14cef..2ae1dcfd899 100644 --- a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs +++ b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs @@ -1,11 +1,8 @@ -#nullable enable - -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Avalonia.Controls.Platform; using Avalonia.Platform; using Avalonia.Platform.Interop; using Avalonia.Platform.Storage; diff --git a/src/Avalonia.X11/SMLib.cs b/src/Avalonia.X11/SMLib.cs index f8f13e32f8f..60c8d5c7fe4 100644 --- a/src/Avalonia.X11/SMLib.cs +++ b/src/Avalonia.X11/SMLib.cs @@ -1,4 +1,3 @@ -#nullable enable using System; using System.Runtime.InteropServices; diff --git a/src/Avalonia.X11/Screens/X11Screen.Providers.cs b/src/Avalonia.X11/Screens/X11Screen.Providers.cs index 0d3a620c1a5..82eb21b2871 100644 --- a/src/Avalonia.X11/Screens/X11Screen.Providers.cs +++ b/src/Avalonia.X11/Screens/X11Screen.Providers.cs @@ -1,10 +1,10 @@ - -#nullable enable using System; +using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using Avalonia.Platform; using static Avalonia.X11.XLib; + namespace Avalonia.X11.Screens; internal partial class X11Screens @@ -44,7 +44,7 @@ public virtual void Refresh() private unsafe Size? GetPhysicalMonitorSizeFromEDID(IntPtr rrOutput) { - if (rrOutput == IntPtr.Zero || x11 == null) + if (rrOutput == IntPtr.Zero) return null; var properties = XRRListOutputProperties(x11.Display, rrOutput, out int propertyCount); var hasEDID = false; @@ -130,7 +130,7 @@ internal interface IX11RawScreenInfoProvider { nint[] ScreenKeys { get; } event Action? Changed; - X11Screen? CreateScreenFromKey(nint key); + X11Screen CreateScreenFromKey(nint key); } internal unsafe struct MonitorInfo @@ -211,20 +211,18 @@ private unsafe MonitorInfo[] MonitorInfos } } - public X11Screen? CreateScreenFromKey(nint key) + public X11Screen CreateScreenFromKey(nint key) { - var info = MonitorInfos.Where(x => x.Name == key).FirstOrDefault(); - var infos = MonitorInfos; for (var i = 0; i < infos.Length; i++) { if (infos[i].Name == key) { - return new X11Screen(info, _x11, _scalingProvider, i); + return new X11Screen(infos[i], _x11, _scalingProvider, i); } } - return null; + throw new ArgumentOutOfRangeException(nameof(key)); } } @@ -248,7 +246,7 @@ public FallbackScreensImpl(AvaloniaX11Platform platform) private bool UpdateRootWindowGeometry() => XGetGeometry(_info.Display, _info.RootWindow, out _geo); - public X11Screen? CreateScreenFromKey(nint key) + public X11Screen CreateScreenFromKey(nint key) { return new FallBackScreen(new PixelRect(0, 0, _geo.width, _geo.height), _info); } diff --git a/src/Avalonia.X11/Screens/X11Screens.Scaling.cs b/src/Avalonia.X11/Screens/X11Screens.Scaling.cs index c6d14d3253d..3398580750b 100644 --- a/src/Avalonia.X11/Screens/X11Screens.Scaling.cs +++ b/src/Avalonia.X11/Screens/X11Screens.Scaling.cs @@ -1,4 +1,3 @@ -#nullable enable using System; using System.Collections.Generic; using System.Globalization; diff --git a/src/Avalonia.X11/Screens/X11Screens.cs b/src/Avalonia.X11/Screens/X11Screens.cs index 5df34555b7b..b8ff80734c6 100644 --- a/src/Avalonia.X11/Screens/X11Screens.cs +++ b/src/Avalonia.X11/Screens/X11Screens.cs @@ -1,12 +1,7 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading.Tasks; using Avalonia.Platform; using static Avalonia.X11.Screens.X11Screens; -using static Avalonia.X11.XLib; namespace Avalonia.X11.Screens { diff --git a/src/Avalonia.X11/TransparencyHelper.cs b/src/Avalonia.X11/TransparencyHelper.cs index dd70643cfdb..50a73a36ce2 100644 --- a/src/Avalonia.X11/TransparencyHelper.cs +++ b/src/Avalonia.X11/TransparencyHelper.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using Avalonia.Controls; -#nullable enable - namespace Avalonia.X11 { internal class TransparencyHelper : IDisposable diff --git a/src/Avalonia.X11/Vulkan/VulkanSupport.cs b/src/Avalonia.X11/Vulkan/VulkanSupport.cs index 5139d78880f..5f9dcf7953e 100644 --- a/src/Avalonia.X11/Vulkan/VulkanSupport.cs +++ b/src/Avalonia.X11/Vulkan/VulkanSupport.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; using System.Collections.Generic; using System.Runtime.InteropServices; diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs index b00879bd1dd..ad4b841e1eb 100644 --- a/src/Avalonia.X11/X11Atoms.cs +++ b/src/Avalonia.X11/X11Atoms.cs @@ -222,7 +222,7 @@ public IntPtr GetAtom(string name) return atom; } - public string GetAtomName(IntPtr atom) + public string? GetAtomName(IntPtr atom) { if (_atomsToNames.TryGetValue(atom, out var rv)) return rv; diff --git a/src/Avalonia.X11/X11Clipboard.cs b/src/Avalonia.X11/X11Clipboard.cs index 637d44d6171..da079458d93 100644 --- a/src/Avalonia.X11/X11Clipboard.cs +++ b/src/Avalonia.X11/X11Clipboard.cs @@ -12,11 +12,11 @@ namespace Avalonia.X11 internal class X11Clipboard : IClipboard { private readonly X11Info _x11; - private IDataObject _storedDataObject; + private IDataObject? _storedDataObject; private IntPtr _handle; - private TaskCompletionSource _storeAtomTcs; - private TaskCompletionSource _requestedFormatsTcs; - private TaskCompletionSource _requestedDataTcs; + private TaskCompletionSource? _storeAtomTcs; + private TaskCompletionSource? _requestedFormatsTcs; + private TaskCompletionSource? _requestedDataTcs; private readonly IntPtr[] _textAtoms; private readonly IntPtr _avaloniaSaveTargetsAtom; @@ -39,7 +39,7 @@ private bool IsStringAtom(IntPtr atom) return _textAtoms.Contains(atom); } - private Encoding GetStringEncoding(IntPtr atom) + private Encoding? GetStringEncoding(IntPtr atom) { return (atom == _x11.Atoms.XA_STRING || atom == _x11.Atoms.OEMTEXT) @@ -86,7 +86,7 @@ private unsafe void OnEvent(ref XEvent ev) IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property) { - Encoding textEnc; + Encoding? textEnc; if (target == _x11.Atoms.TARGETS) { var atoms = ConvertDataObject(_storedDataObject); @@ -136,9 +136,9 @@ IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property) return property; } - else if(_storedDataObject?.Contains(_x11.Atoms.GetAtomName(target)) == true) + else if(_x11.Atoms.GetAtomName(target) is { } atomName && _storedDataObject?.Contains(atomName) == true) { - var objValue = _storedDataObject.Get(_x11.Atoms.GetAtomName(target)); + var objValue = _storedDataObject.Get(atomName); if(!(objValue is byte[] bytes)) { @@ -167,7 +167,7 @@ IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property) } XGetWindowProperty(_x11.Display, _handle, sel.property, IntPtr.Zero, new IntPtr (0x7fffffff), true, (IntPtr)Atom.AnyPropertyType, out var actualTypeAtom, out var actualFormat, out var nitems, out var bytes_after, out var prop); - Encoding textEnc = null; + Encoding? textEnc; if (nitems == IntPtr.Zero) { _requestedFormatsTcs?.TrySetResult(null); @@ -196,7 +196,7 @@ IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property) if (actualTypeAtom == _x11.Atoms.INCR) { // TODO: Actually implement that monstrosity - _requestedDataTcs.TrySetResult(null); + _requestedDataTcs?.TrySetResult(null); } else { @@ -211,26 +211,26 @@ IntPtr WriteTargetToProperty(IntPtr target, IntPtr window, IntPtr property) } } - private Task SendFormatRequest() + private Task SendFormatRequest() { if (_requestedFormatsTcs == null || _requestedFormatsTcs.Task.IsCompleted) - _requestedFormatsTcs = new TaskCompletionSource(); + _requestedFormatsTcs = new TaskCompletionSource(); XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, _x11.Atoms.TARGETS, _x11.Atoms.TARGETS, _handle, IntPtr.Zero); return _requestedFormatsTcs.Task; } - private Task SendDataRequest(IntPtr format) + private Task SendDataRequest(IntPtr format) { if (_requestedDataTcs == null || _requestedDataTcs.Task.IsCompleted) - _requestedDataTcs = new TaskCompletionSource(); + _requestedDataTcs = new TaskCompletionSource(); XConvertSelection(_x11.Display, _x11.Atoms.CLIPBOARD, format, format, _handle, IntPtr.Zero); return _requestedDataTcs.Task; } private bool HasOwner => XGetSelectionOwner(_x11.Display, _x11.Atoms.CLIPBOARD) != IntPtr.Zero; - public async Task GetTextAsync() + public async Task GetTextAsync() { if (!HasOwner) return null; @@ -247,21 +247,26 @@ public async Task GetTextAsync() } } - return (string)await SendDataRequest(target); + return (string?)await SendDataRequest(target); } - private IntPtr[] ConvertDataObject(IDataObject data) + private IntPtr[] ConvertDataObject(IDataObject? data) { var atoms = new HashSet { _x11.Atoms.TARGETS, _x11.Atoms.MULTIPLE }; - foreach (var fmt in data.GetDataFormats()) + + if (data is not null) { - if (fmt == DataFormats.Text) - foreach (var ta in _textAtoms) - atoms.Add(ta); - else - atoms.Add(_x11.Atoms.GetAtom(fmt)); + foreach (var fmt in data.GetDataFormats()) + { + if (fmt == DataFormats.Text) + foreach (var ta in _textAtoms) + atoms.Add(ta); + else + atoms.Add(_x11.Atoms.GetAtom(fmt)); + } } + return atoms.ToArray(); } @@ -287,10 +292,13 @@ private Task StoreAtomsInClipboardManager(IDataObject data) return Task.CompletedTask; } - public Task SetTextAsync(string text) + public Task SetTextAsync(string? text) { var data = new DataObject(); - data.Set(DataFormats.Text, text); + + if (text is not null) + data.Set(DataFormats.Text, text); + return SetDataObjectAsync(data); } @@ -309,19 +317,26 @@ public Task SetDataObjectAsync(IDataObject data) public async Task GetFormatsAsync() { if (!HasOwner) - return null; + return []; + var res = await SendFormatRequest(); if (res == null) - return null; + return []; + var rv = new List(); if (_textAtoms.Any(res.Contains)) rv.Add(DataFormats.Text); + foreach (var t in res) - rv.Add(_x11.Atoms.GetAtomName(t)); + { + if (_x11.Atoms.GetAtomName(t) is { } atomName) + rv.Add(atomName); + } + return rv.ToArray(); } - public async Task GetDataAsync(string format) + public async Task GetDataAsync(string format) { if (!HasOwner) return null; @@ -330,7 +345,7 @@ public async Task GetDataAsync(string format) var formatAtom = _x11.Atoms.GetAtom(format); var res = await SendFormatRequest(); - if (!res.Contains(formatAtom)) + if (res is null || !res.Contains(formatAtom)) return null; return await SendDataRequest(formatAtom); diff --git a/src/Avalonia.X11/X11CursorFactory.cs b/src/Avalonia.X11/X11CursorFactory.cs index bd0413b1db8..fdd8a318064 100644 --- a/src/Avalonia.X11/X11CursorFactory.cs +++ b/src/Avalonia.X11/X11CursorFactory.cs @@ -6,8 +6,6 @@ using Avalonia.Platform; using Avalonia.Platform.Internal; -#nullable enable - namespace Avalonia.X11 { internal partial class X11CursorFactory : ICursorFactory diff --git a/src/Avalonia.X11/X11FramebufferSurface.cs b/src/Avalonia.X11/X11FramebufferSurface.cs index f3cfc2ae908..5b01ce91dea 100644 --- a/src/Avalonia.X11/X11FramebufferSurface.cs +++ b/src/Avalonia.X11/X11FramebufferSurface.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Platform; diff --git a/src/Avalonia.X11/X11Globals.cs b/src/Avalonia.X11/X11Globals.cs index 80e1eebd166..c2593bf1852 100644 --- a/src/Avalonia.X11/X11Globals.cs +++ b/src/Avalonia.X11/X11Globals.cs @@ -1,8 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; using static Avalonia.X11.XLib; + namespace Avalonia.X11 { internal unsafe class X11Globals @@ -13,14 +12,14 @@ internal unsafe class X11Globals private readonly IntPtr _rootWindow; private readonly IntPtr _compositingAtom; - private string _wmName; + private string? _wmName; private IntPtr _compositionAtomOwner; private bool _isCompositionEnabled; - public event Action WindowManagerChanged; - public event Action CompositionChanged; - public event Action RootPropertyChanged; - public event Action RootGeometryChangedChanged; + public event Action? WindowManagerChanged; + public event Action? CompositionChanged; + public event Action? RootPropertyChanged; + public event Action? RootGeometryChangedChanged; public X11Globals(AvaloniaX11Platform plat) { @@ -36,7 +35,7 @@ public X11Globals(AvaloniaX11Platform plat) UpdateCompositingAtomOwner(); } - public string WmName + public string? WmName { get => _wmName; private set @@ -131,7 +130,7 @@ private void HandleCompositionAtomOwnerEvents(ref XEvent ev) private void UpdateWmName() => WmName = GetWmName(); - private string GetWmName() + private string? GetWmName() { var wm = GetSupportingWmCheck(_rootWindow); if (wm == IntPtr.Zero || wm != GetSupportingWmCheck(wm)) diff --git a/src/Avalonia.X11/X11IconLoader.cs b/src/Avalonia.X11/X11IconLoader.cs index 73b24bb4c51..bde6de66148 100644 --- a/src/Avalonia.X11/X11IconLoader.cs +++ b/src/Avalonia.X11/X11IconLoader.cs @@ -33,7 +33,7 @@ internal unsafe class X11IconData : IWindowIconImpl, IFramebufferPlatformSurface { private int _width; private int _height; - private uint[] _bdata; + private uint[]? _bdata; public UIntPtr[] Data { get; } public X11IconData(Bitmap bitmap) diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index e6ef066572f..cc4ec67a3a5 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -19,13 +19,13 @@ internal unsafe class X11Info public int RandrEventBase { get; } public int RandrErrorBase { get; } - public Version RandrVersion { get; } + public Version? RandrVersion { get; } public int XInputOpcode { get; } public int XInputEventBase { get; } public int XInputErrorBase { get; } - public Version XInputVersion { get; } + public Version? XInputVersion { get; } public IntPtr LastActivityTimestamp { get; set; } public XVisualInfo? TransparentVisualInfo { get; } diff --git a/src/Avalonia.X11/X11NativeControlHost.cs b/src/Avalonia.X11/X11NativeControlHost.cs index 09254a032f7..cf1218df1e2 100644 --- a/src/Avalonia.X11/X11NativeControlHost.cs +++ b/src/Avalonia.X11/X11NativeControlHost.cs @@ -1,8 +1,9 @@ using System; +using System.Diagnostics.CodeAnalysis; using Avalonia.Controls.Platform; using Avalonia.Platform; -using Avalonia.VisualTree; using static Avalonia.X11.XLib; + namespace Avalonia.X11 { // TODO: Actually implement XEmbed instead of simply using XReparentWindow @@ -25,7 +26,7 @@ public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHa public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) { var holder = new DumbWindow(_platform.Info, true, Window.Handle.Handle); - Attachment attachment = null; + Attachment? attachment = null; try { var child = create(holder); @@ -38,7 +39,7 @@ public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func _attachedTo; set { CheckDisposed(); - _attachedTo = (X11NativeControlHost)value; - if (value == null) + _attachedTo = (X11NativeControlHost?)value; + if (_attachedTo is null) { _mapped = false; XUnmapWindow(_display, _holder.Handle); @@ -164,7 +167,8 @@ public void HideWithSize(Size size) if (_mapped) { _mapped = false; - XUnmapWindow(_display, _holder.Handle); + if (_holder is not null) + XUnmapWindow(_display, _holder.Handle); } size *= _attachedTo.Window.RenderScaling; diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 4b1b3731b79..bebae3f0ae8 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -28,15 +28,15 @@ internal class AvaloniaX11Platform : IWindowingPlatform private Lazy _keyboardDevice = new Lazy(() => new KeyboardDevice()); public KeyboardDevice KeyboardDevice => _keyboardDevice.Value; public Dictionary Windows { get; } = new (); - public XI2Manager XI2 { get; private set; } - public X11Info Info { get; private set; } - public X11Screens X11Screens { get; private set; } - public Compositor Compositor { get; private set; } - public IScreenImpl Screens { get; private set; } - public X11PlatformOptions Options { get; private set; } + public XI2Manager? XI2 { get; private set; } + public X11Info Info { get; private set; } = null!; + public X11Screens X11Screens { get; private set; } = null!; + public Compositor Compositor { get; private set; } = null!; + public IScreenImpl Screens { get; private set; } = null!; + public X11PlatformOptions Options { get; private set; } = null!; public IntPtr OrphanedWindow { get; private set; } - public X11Globals Globals { get; private set; } - public XResources Resources { get; private set; } + public X11Globals Globals { get; private set; } = null!; + public XResources Resources { get; private set; } = null!; public ManualRawEventGrouperDispatchQueue EventGrouperDispatchQueue { get; } = new(); public void Initialize(X11PlatformOptions options) @@ -90,9 +90,7 @@ public void Initialize(X11PlatformOptions options) Screens = X11Screens = new X11Screens(this); if (Info.XInputVersion != null) { - var xi2 = new XI2Manager(); - if (xi2.Init(this)) - XI2 = xi2; + XI2 = XI2Manager.TryCreate(this); } var graphics = InitializeGraphics(options, Info); @@ -108,7 +106,7 @@ public void Initialize(X11PlatformOptions options) public IntPtr DeferredDisplay { get; set; } public IntPtr Display { get; set; } - private static uint[] X11IconConverter(IWindowIconImpl icon) + private static uint[] X11IconConverter(IWindowIconImpl? icon) { if (!(icon is X11IconData x11icon)) return Array.Empty(); @@ -187,7 +185,7 @@ private static bool ShouldUseXim() return false; } - private static IPlatformGraphics InitializeGraphics(X11PlatformOptions opts, X11Info info) + private static IPlatformGraphics? InitializeGraphics(X11PlatformOptions opts, X11Info info) { if (opts.RenderingMode is null || !opts.RenderingMode.Any()) { @@ -354,7 +352,7 @@ public class X11PlatformOptions }; - public string WmClass { get; set; } + public string? WmClass { get; set; } /// /// Enables multitouch support. The default value is true. @@ -392,7 +390,7 @@ public X11PlatformOptions() { try { - WmClass = Assembly.GetEntryAssembly()?.GetName()?.Name; + WmClass = Assembly.GetEntryAssembly()?.GetName().Name; } catch { @@ -412,7 +410,7 @@ public static AppBuilder UseX11(this AppBuilder builder) return builder; } - public static void InitializeX11Platform(X11PlatformOptions options = null) => + public static void InitializeX11Platform(X11PlatformOptions? options = null) => new AvaloniaX11Platform().Initialize(options ?? new X11PlatformOptions()); } diff --git a/src/Avalonia.X11/X11PlatformLifetimeEvents.cs b/src/Avalonia.X11/X11PlatformLifetimeEvents.cs index f03ed6f1ef3..84b790ec2ec 100644 --- a/src/Avalonia.X11/X11PlatformLifetimeEvents.cs +++ b/src/Avalonia.X11/X11PlatformLifetimeEvents.cs @@ -1,4 +1,3 @@ -#nullable enable using System; using System.Text; using System.Collections.Concurrent; @@ -232,7 +231,7 @@ private void ActualInteractHandler(object? state) { var e = new ShutdownRequestedEventArgs(); - if (_platform.Options?.EnableSessionManagement ?? false) + if (_platform.Options.EnableSessionManagement) { ShutdownRequested?.Invoke(this, e); } diff --git a/src/Avalonia.X11/X11Structs.cs b/src/Avalonia.X11/X11Structs.cs index 86ef7879a5e..1682ad4bb5d 100644 --- a/src/Avalonia.X11/X11Structs.cs +++ b/src/Avalonia.X11/X11Structs.cs @@ -666,7 +666,7 @@ public static string ToString (object ev) if (!string.IsNullOrEmpty(result)) { result += ", "; } - object value = fields [i].GetValue (ev); + var value = fields [i].GetValue(ev); result += fields [i].Name + "=" + (value == null ? "" : value.ToString ()); } return type.Name + " (" + result + ")"; diff --git a/src/Avalonia.X11/X11Window.Ime.cs b/src/Avalonia.X11/X11Window.Ime.cs index f27a33ec54c..a5a0df926ad 100644 --- a/src/Avalonia.X11/X11Window.Ime.cs +++ b/src/Avalonia.X11/X11Window.Ime.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; using System.Collections.Generic; using System.Runtime.InteropServices; diff --git a/src/Avalonia.X11/X11Window.Xim.cs b/src/Avalonia.X11/X11Window.Xim.cs index e016908484f..faf208fb68c 100644 --- a/src/Avalonia.X11/X11Window.Xim.cs +++ b/src/Avalonia.X11/X11Window.Xim.cs @@ -1,5 +1,3 @@ -#nullable enable - using System; using System.Threading.Tasks; using Avalonia.FreeDesktop; diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index c68c55e0421..ceb9c5edb8a 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -30,8 +30,6 @@ // ReSharper disable IdentifierTypo // ReSharper disable StringLiteralTypo -#nullable enable - namespace Avalonia.X11 { internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client, @@ -95,7 +93,7 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, X11Wind _mode = mode; _mode.Init(this); _popup = popupParent != null; - _overrideRedirect = _popup || overrideRedirect; + _overrideRedirect = _popup || overrideRedirect; _x11 = platform.Info; _mouse = new MouseDevice(); _touch = new TouchDevice(); @@ -1256,7 +1254,7 @@ public void SetTitle(string? title) } } - public void SetWmClass(IntPtr handle, string wmClass) + public void SetWmClass(IntPtr handle, string? wmClass) { // See https://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS // We don't actually parse the application's command line, so we only use RESOURCE_NAME and argv[0] diff --git a/src/Avalonia.X11/X11WindowModes/InputProxyWindowMode.cs b/src/Avalonia.X11/X11WindowModes/InputProxyWindowMode.cs index 7716cd1464e..b7afa3eaf03 100644 --- a/src/Avalonia.X11/X11WindowModes/InputProxyWindowMode.cs +++ b/src/Avalonia.X11/X11WindowModes/InputProxyWindowMode.cs @@ -8,7 +8,7 @@ partial class X11Window { public class InputProxyWindowMode : DefaultTopLevelWindowMode { - private X11FocusProxy _focusProxy; + private X11FocusProxy? _focusProxy; public override void OnHandleCreated(IntPtr handle) { @@ -52,4 +52,4 @@ public override void AppendWmProtocols(List data) base.AppendWmProtocols(data); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/X11WindowModes/WindowMode.cs b/src/Avalonia.X11/X11WindowModes/WindowMode.cs index 67dff91131e..20df7d93e92 100644 --- a/src/Avalonia.X11/X11WindowModes/WindowMode.cs +++ b/src/Avalonia.X11/X11WindowModes/WindowMode.cs @@ -7,10 +7,10 @@ partial class X11Window { public abstract class X11WindowMode { - public X11Window Window { get; private set; } + public X11Window Window { get; private set; } = null!; protected IntPtr Display; - protected X11Info X11; - protected AvaloniaX11Platform Platform; + protected X11Info X11 = null!; + protected AvaloniaX11Platform Platform = null!; protected IntPtr Handle => Window._handle; protected IntPtr RenderHandle => Window._renderHandle; public virtual bool BlockInput => false; @@ -57,4 +57,4 @@ public virtual void Hide() { } } -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/X11WindowModes/XEmbedClientWindowMode.cs b/src/Avalonia.X11/X11WindowModes/XEmbedClientWindowMode.cs index 1c805fd8438..89ceec5813e 100644 --- a/src/Avalonia.X11/X11WindowModes/XEmbedClientWindowMode.cs +++ b/src/Avalonia.X11/X11WindowModes/XEmbedClientWindowMode.cs @@ -1,6 +1,4 @@ -#nullable enable using System; -using System.ComponentModel; using Avalonia.Controls; using Avalonia.Controls.Embedding; using Avalonia.Input; @@ -73,7 +71,10 @@ void SendXEmbedMessage(XEmbedMessage message, IntPtr detail = default, IntPtr da static XEmbedClientWindowMode() { - KeyboardDevice.Instance.PropertyChanged += (_, args) => + if (KeyboardDevice.Instance is not { } keyboardDevice) + return; + + keyboardDevice.PropertyChanged += (_, args) => { if (args.PropertyName == nameof(KeyboardDevice.Instance.FocusedElement)) { @@ -204,4 +205,4 @@ public override PixelPoint PointToScreen(Point point) => (int)(point.Y * Window.RenderScaling)) + GetWindowOffset(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/XEmbedPlug.cs b/src/Avalonia.X11/XEmbedPlug.cs index b42daed34b7..f0e3df688ec 100644 --- a/src/Avalonia.X11/XEmbedPlug.cs +++ b/src/Avalonia.X11/XEmbedPlug.cs @@ -9,14 +9,14 @@ namespace Avalonia.X11; public class XEmbedPlug : IDisposable { - private EmbeddableControlRoot _root; + private EmbeddableControlRoot? _root; private Color _backgroundColor; private readonly X11Info _x11; private readonly X11Window.XEmbedClientWindowMode _mode; private XEmbedPlug(IntPtr? parentXid) { - var platform = AvaloniaLocator.Current.GetService(); + var platform = AvaloniaLocator.Current.GetRequiredService(); _mode = new X11Window.XEmbedClientWindowMode(); _root = new EmbeddableControlRoot(new X11Window(platform, null, _mode)); _root.Prepare(); @@ -28,13 +28,16 @@ private XEmbedPlug(IntPtr? parentXid) XLib.XSync(platform.Display, false); } + private EmbeddableControlRoot Root + => _root ?? throw new ObjectDisposedException(nameof(XEmbedPlug)); + public IntPtr Handle => - _root?.PlatformImpl!.Handle!.Handle ?? throw new ObjectDisposedException(nameof(XEmbedPlug)); + Root.PlatformImpl!.Handle!.Handle; - public object Content + public object? Content { - get => _root.Content; - set => _root.Content = value; + get => Root.Content; + set => Root.Content = value; } public Color BackgroundColor @@ -58,7 +61,7 @@ public double ScaleFactor public void ProcessInteractiveResize(PixelSize size) { - var events = (IX11PlatformDispatcher)AvaloniaLocator.Current.GetService(); + var events = (IX11PlatformDispatcher)AvaloniaLocator.Current.GetRequiredService(); events.EventDispatcher.DispatchX11Events(CancellationToken.None); _mode.ProcessInteractiveResize(size); Dispatcher.UIThread.RunJobs(DispatcherPriority.UiThreadRender); @@ -78,4 +81,4 @@ public void Dispose() public static XEmbedPlug Create(IntPtr embedderXid) => embedderXid == IntPtr.Zero ? throw new ArgumentException() : new XEmbedPlug(embedderXid); -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/XEmbedTrayIconImpl.cs b/src/Avalonia.X11/XEmbedTrayIconImpl.cs index c046e49f934..7858c96d624 100644 --- a/src/Avalonia.X11/XEmbedTrayIconImpl.cs +++ b/src/Avalonia.X11/XEmbedTrayIconImpl.cs @@ -26,12 +26,12 @@ public void Dispose() NotImplemented(); } - public void SetIcon(IWindowIconImpl icon) + public void SetIcon(IWindowIconImpl? icon) { NotImplemented(); } - public void SetToolTipText(string text) + public void SetToolTipText(string? text) { NotImplemented(); } @@ -41,7 +41,7 @@ public void SetIsVisible(bool visible) NotImplemented(); } - public INativeMenuExporter MenuExporter { get; } - public Action OnClicked { get; set; } + public INativeMenuExporter? MenuExporter { get; } + public Action? OnClicked { get; set; } } } diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs index 0f7c71eb55e..ce93c9d3c91 100644 --- a/src/Avalonia.X11/XI2Manager.cs +++ b/src/Avalonia.X11/XI2Manager.cs @@ -1,12 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Runtime.InteropServices; - using Avalonia.Input; using Avalonia.Input.Raw; -using Avalonia.Platform; using static Avalonia.X11.XLib; namespace Avalonia.X11 @@ -37,8 +33,8 @@ internal unsafe class XI2Manager private class DeviceInfo { public int Id { get; } - public XIValuatorClassInfo[] Valuators { get; private set; } - public XIScrollClassInfo[] Scrollers { get; private set; } + public XIValuatorClassInfo[] Valuators { get; private set; } = []; + public XIScrollClassInfo[] Scrollers { get; private set; } = []; public DeviceInfo(XIDeviceInfo info) { Id = info.Deviceid; @@ -146,48 +142,47 @@ public bool HasMotion(ParsedDeviceEvent ev) public XIValuatorClassInfo? TouchMinorXIValuatorClassInfo { get; private set; } } - private PointerDeviceInfo _pointerDevice; - private AvaloniaX11Platform _platform; + private readonly PointerDeviceInfo _pointerDevice; + private readonly AvaloniaX11Platform _platform; - public bool Init(AvaloniaX11Platform platform) + private XI2Manager(AvaloniaX11Platform platform, PointerDeviceInfo pointerDevice) { _platform = platform; _x11 = platform.Info; - _multitouch = platform.Options?.EnableMultiTouch ?? true; - var devices = (XIDeviceInfo*) XIQueryDevice(_x11.Display, + _multitouch = platform.Options.EnableMultiTouch ?? true; + _pointerDevice = pointerDevice; + } + + public static XI2Manager? TryCreate(AvaloniaX11Platform platform) + { + var x11 = platform.Info; + + var devices = (XIDeviceInfo*) XIQueryDevice(x11.Display, (int)XiPredefinedDeviceId.XIAllMasterDevices, out int num); + + PointerDeviceInfo? pointerDevice = null; + for (var c = 0; c < num; c++) { if (devices[c].Use == XiDeviceType.XIMasterPointer) { - _pointerDevice = new PointerDeviceInfo(devices[c], _x11); + pointerDevice = new PointerDeviceInfo(devices[c], x11); break; } } - if(_pointerDevice == null) - return false; - /* - int mask = 0; - - XISetMask(ref mask, XiEventType.XI_DeviceChanged); - var emask = new XIEventMask - { - Mask = &mask, - Deviceid = _pointerDevice.Id, - MaskLen = XiEventMaskLen - }; - - if (XISelectEvents(_x11.Display, _x11.RootWindow, &emask, 1) != Status.Success) - return false; - return true; - */ - return XiSelectEvents(_x11.Display, _x11.RootWindow, new Dictionary> - { - [_pointerDevice.Id] = new List - { - XiEventType.XI_DeviceChanged - } - }) == Status.Success; + + if (pointerDevice is null) + return null; + + var status = XiSelectEvents( + x11.Display, + x11.RootWindow, + new Dictionary> { [pointerDevice.Id] = [XiEventType.XI_DeviceChanged] }); + + if (status != Status.Success) + return null; + + return new XI2Manager(platform, pointerDevice); } public XEventMask AddWindow(IntPtr xid, IXI2Client window) @@ -309,11 +304,9 @@ private void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev) { var pixelPoint = new PixelPoint((int)ev.RootPosition.X, (int)ev.RootPosition.Y); var screen = _platform.Screens.ScreenFromPoint(pixelPoint); - var screenBoundsFromPoint = screen?.Bounds; - Debug.Assert(screenBoundsFromPoint != null); - if (screenBoundsFromPoint != null) + if (screen?.Bounds is { } screenBoundsFromPoint) { - screenBounds = screenBoundsFromPoint.Value; + screenBounds = screenBoundsFromPoint; // As https://www.kernel.org/doc/html/latest/input/multi-touch-protocol.html says, using `screenBounds.Width` is not accurate enough. touchMajor = (touchMajorValue - touchMajorXIValuatorClassInfo.Min) / diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 33daacf9365..a11bfce2118 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -148,7 +148,7 @@ public static extern int XInternAtoms(IntPtr display, string[] atom_names, int a [DllImport(libX11)] public static extern IntPtr XGetAtomName(IntPtr display, IntPtr atom); - public static string GetAtomName(IntPtr display, IntPtr atom) + public static string? GetAtomName(IntPtr display, IntPtr atom) { var ptr = XGetAtomName(display, atom); if (ptr == IntPtr.Zero) @@ -511,8 +511,8 @@ public static extern IntPtr XCreateIC(IntPtr xim, string xnClientWindow, IntPtr [DllImport(libX11)] public static extern IntPtr XCreateIC(IntPtr xim, string xnClientWindow, IntPtr handle, string xnFocusWindow, - IntPtr value2, string xnInputStyle, IntPtr value3, string xnResourceName, string optionsWmClass, - string xnResourceClass, string wmClass, string xnPreeditAttributes, IntPtr list, IntPtr zero); + IntPtr value2, string xnInputStyle, IntPtr value3, string xnResourceName, string? optionsWmClass, + string xnResourceClass, string? wmClass, string xnPreeditAttributes, IntPtr list, IntPtr zero); [DllImport(libX11)] public static extern void XSetICFocus(IntPtr xic); diff --git a/src/Avalonia.X11/XResources.cs b/src/Avalonia.X11/XResources.cs index 52df657ce9a..ee1a0d5d991 100644 --- a/src/Avalonia.X11/XResources.cs +++ b/src/Avalonia.X11/XResources.cs @@ -1,8 +1,8 @@ -#nullable enable using System; using System.Collections.Generic; using System.Runtime.InteropServices; using static Avalonia.X11.XLib; + namespace Avalonia.X11; internal class XResources