فهرست منبع

Merge branch 'master' into fix/relative-layout-crash-with-infinite-size

Dan Walmsley 3 سال پیش
والد
کامیت
dbac7608ba
23فایلهای تغییر یافته به همراه663 افزوده شده و 389 حذف شده
  1. 0 4
      samples/ControlCatalog.NetCore/Program.cs
  2. 2 2
      samples/ControlCatalog/Pages/PointerCanvas.cs
  3. 1 1
      samples/ControlCatalog/Pages/PointersPage.xaml.cs
  4. 0 12
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  5. 13 4
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  6. 251 0
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs
  7. 0 85
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
  8. 15 15
      src/Avalonia.Base/Input/PointerPoint.cs
  9. 4 0
      src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs
  10. 9 6
      src/Avalonia.Base/Media/KnownColors.cs
  11. 14 1
      src/Avalonia.Base/VisualTree/VisualExtensions.cs
  12. 1 0
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  13. 0 10
      src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs
  14. 1 2
      src/Avalonia.Dialogs/ManagedFileChooser.cs
  15. 156 163
      src/Avalonia.X11/X11Atoms.cs
  16. 6 2
      src/Avalonia.X11/X11CursorFactory.cs
  17. 14 1
      src/Avalonia.X11/X11Platform.cs
  18. 0 3
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  19. 8 0
      src/Shared/SourceGeneratorAttributes.cs
  20. 1 69
      src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs
  21. 0 9
      src/Windows/Avalonia.Win32/Win32Platform.cs
  22. 94 0
      src/tools/DevGenerators/EnumMemberDictionaryGenerator.cs
  23. 73 0
      src/tools/DevGenerators/X11AtomsGenerator.cs

+ 0 - 4
samples/ControlCatalog.NetCore/Program.cs

@@ -115,10 +115,6 @@ namespace ControlCatalog.NetCore
                     UseDBusMenu = true,
                     EnableIme = true
                 })
-                .With(new Win32PlatformOptions
-                {
-                    EnableMultitouch = true
-                })
                 .UseSkia()
                 .AfterSetup(builder =>
                 {

+ 2 - 2
samples/ControlCatalog/Pages/PointerCanvas.cs

@@ -174,9 +174,9 @@ Twist: {_lastProperties?.Twist}";
         var lastPointer = e.GetCurrentPoint(this);
         _lastProperties = lastPointer.Properties;
 
-        if (_lastProperties.PointerUpdateKind != PointerUpdateKind.Other)
+        if (_lastProperties?.PointerUpdateKind != PointerUpdateKind.Other)
         {
-            _lastNonOtherUpdateKind = _lastProperties.PointerUpdateKind;
+            _lastNonOtherUpdateKind = _lastProperties?.PointerUpdateKind;
         }
 
         if (e.RoutedEvent == PointerReleasedEvent && e.Pointer.Type == PointerType.Touch)

+ 1 - 1
samples/ControlCatalog/Pages/PointersPage.xaml.cs

@@ -62,7 +62,7 @@ Position: ??? ???";
             e.Pointer.Capture(null);
             e.Handled = true;
         }
-        else
+        else if (e.Pointer.Captured is not null)
         {
             throw new InvalidOperationException("How?");
         }

+ 0 - 12
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@@ -47,18 +47,6 @@ namespace Avalonia.Android
             }
         }
 
-        [Obsolete("deprecated")]
-        public override void Invalidate(global::Android.Graphics.Rect dirty)
-        {
-            Invalidate();
-        }
-
-        [Obsolete("deprecated")]
-        public override void Invalidate(int l, int t, int r, int b)
-        {
-            Invalidate();
-        }
-
         public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
         {
             Log.Info("AVALONIA", "Surface Changed");

+ 13 - 4
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+
 using Android.Content;
 using Android.Graphics;
 using Android.Views;
@@ -30,7 +31,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
         private readonly IFramebufferPlatformSurface _framebuffer;
 
         private readonly AndroidKeyboardEventsHelper<TopLevelImpl> _keyboardHelper;
-        private readonly AndroidTouchEventsHelper<TopLevelImpl> _touchHelper;
+        private readonly AndroidMotionEventsHelper _pointerHelper;
         private readonly ITextInputMethodImpl _textInputMethod;
         private ViewImpl _view;
 
@@ -39,8 +40,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
             _view = new ViewImpl(avaloniaView.Context, this, placeOnTop);
             _textInputMethod = new AndroidInputMethod<ViewImpl>(_view);
             _keyboardHelper = new AndroidKeyboardEventsHelper<TopLevelImpl>(this);
-            _touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(this, () => InputRoot,
-                GetAvaloniaPointFromEvent);
+            _pointerHelper = new AndroidMotionEventsHelper(this);
             _gl = GlPlatformSurface.TryCreate(this);
             _framebuffer = new FramebufferManager(this);
 
@@ -160,10 +160,19 @@ namespace Avalonia.Android.Platform.SkiaPlatform
                 _tl.Draw();
             }
 
+            protected override bool DispatchGenericPointerEvent(MotionEvent e)
+            {
+                bool callBase;
+                bool? result = _tl._pointerHelper.DispatchMotionEvent(e, out callBase);
+                bool baseResult = callBase ? base.DispatchGenericPointerEvent(e) : false;
+
+                return result != null ? result.Value : baseResult;
+            }
+
             public override bool DispatchTouchEvent(MotionEvent e)
             {
                 bool callBase;
-                bool? result = _tl._touchHelper.DispatchTouchEvent(e, out callBase);
+                bool? result = _tl._pointerHelper.DispatchMotionEvent(e, out callBase);
                 bool baseResult = callBase ? base.DispatchTouchEvent(e) : false;
 
                 return result != null ? result.Value : baseResult;

+ 251 - 0
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidMotionEventsHelper.cs

@@ -0,0 +1,251 @@
+using System;
+using System.Collections.Generic;
+
+using Android.Views;
+
+using Avalonia.Android.Platform.SkiaPlatform;
+using Avalonia.Collections.Pooled;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+
+#nullable enable
+
+namespace Avalonia.Android.Platform.Specific.Helpers
+{
+    internal class AndroidMotionEventsHelper : IDisposable
+    {
+        private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new(ClearMode.Never);
+        private static readonly float s_radiansToDegree = (float)(180f * Math.PI);
+        private readonly TouchDevice _touchDevice;
+        private readonly MouseDevice _mouseDevice;
+        private readonly PenDevice _penDevice;
+        private readonly TopLevelImpl _view;
+        private bool _disposed;
+
+        public AndroidMotionEventsHelper(TopLevelImpl view)
+        {
+            _touchDevice = new TouchDevice();
+            _penDevice = new PenDevice();
+            _mouseDevice = new MouseDevice();
+            _view = view;
+        }
+
+        public bool? DispatchMotionEvent(MotionEvent e, out bool callBase)
+        {
+            callBase = true;
+            if (_disposed)
+            {
+                return null;
+            }
+
+            var eventTime = (ulong)DateTime.Now.Millisecond;
+            var inputRoot = _view.InputRoot;
+            var actionMasked = e.ActionMasked;
+            var modifiers = GetModifiers(e.MetaState, e.ButtonState);
+
+            if (actionMasked == MotionEventActions.Move)
+            {
+                for (int index = 0; index < e.PointerCount; index++)
+                {
+                    var toolType = e.GetToolType(index);
+                    var device = GetDevice(toolType);
+                    var eventType = toolType == MotionEventToolType.Finger ? RawPointerEventType.TouchUpdate : RawPointerEventType.Move;
+                    var point = CreatePoint(e, index);
+                    modifiers |= GetToolModifiers(toolType);
+
+                    // ButtonState reports only mouse buttons, but not touch or stylus pointer.
+                    if (toolType != MotionEventToolType.Mouse)
+                    {
+                        modifiers |= RawInputModifiers.LeftMouseButton;
+                    }
+
+                    var args = new RawTouchEventArgs(device, eventTime, inputRoot, eventType, point, modifiers, e.GetPointerId(index))
+                    {
+                        IntermediatePoints = new Lazy<IReadOnlyList<RawPointerPoint>?>(() =>
+                        {
+                            var site = e.HistorySize;
+                            s_intermediatePointsPooledList.Clear();
+                            s_intermediatePointsPooledList.Capacity = site;
+
+                            for (int pos = 0; pos < site; pos++)
+                            {
+                                s_intermediatePointsPooledList.Add(CreateHistoricalPoint(e, index, pos));
+                            }
+
+                            return s_intermediatePointsPooledList;
+                        })
+                    };
+                    _view.Input(args);
+                }
+            }
+            else
+            {
+                var index = e.ActionIndex;
+                var toolType = e.GetToolType(index);
+                var device = GetDevice(toolType);
+                modifiers |= GetToolModifiers(toolType);
+                var point = CreatePoint(e, index);
+
+                if (actionMasked == MotionEventActions.Scroll && toolType == MotionEventToolType.Mouse)
+                {
+                    var delta = new Vector(e.GetAxisValue(Axis.Hscroll), e.GetAxisValue(Axis.Vscroll));
+                    var args = new RawMouseWheelEventArgs(device, eventTime, inputRoot, point.Position, delta, RawInputModifiers.None);
+                    _view.Input(args);
+                }
+                else
+                {
+                    var eventType = GetActionType(e, actionMasked, toolType);
+                    if (eventType >= 0)
+                    {
+                        var args = new RawTouchEventArgs(device, eventTime, inputRoot, eventType, point, modifiers, e.GetPointerId(index));
+                        _view.Input(args);
+                    }
+                }
+            }
+
+            return true;
+        }
+
+        private static RawInputModifiers GetModifiers(MetaKeyStates metaState, MotionEventButtonState buttonState)
+        {
+            var modifiers = RawInputModifiers.None;
+            if (metaState.HasAnyFlag(MetaKeyStates.ShiftOn))
+            {
+                modifiers |= RawInputModifiers.Shift;
+            }
+            if (metaState.HasAnyFlag(MetaKeyStates.CtrlOn))
+            {
+                modifiers |= RawInputModifiers.Control;
+            }
+            if (metaState.HasAnyFlag(MetaKeyStates.AltOn))
+            {
+                modifiers |= RawInputModifiers.Alt;
+            }
+            if (metaState.HasAnyFlag(MetaKeyStates.MetaOn))
+            {
+                modifiers |= RawInputModifiers.Meta;
+            }
+            if (buttonState.HasAnyFlag(MotionEventButtonState.Primary))
+            {
+                modifiers |= RawInputModifiers.LeftMouseButton;
+            }
+            if (buttonState.HasAnyFlag(MotionEventButtonState.Secondary))
+            {
+                modifiers |= RawInputModifiers.RightMouseButton;
+            }
+            if (buttonState.HasAnyFlag(MotionEventButtonState.Tertiary))
+            {
+                modifiers |= RawInputModifiers.MiddleMouseButton;
+            }
+            if (buttonState.HasAnyFlag(MotionEventButtonState.Back))
+            {
+                modifiers |= RawInputModifiers.XButton1MouseButton;
+            }
+            if (buttonState.HasAnyFlag(MotionEventButtonState.Forward))
+            {
+                modifiers |= RawInputModifiers.XButton2MouseButton;
+            }
+            if (buttonState.HasAnyFlag(MotionEventButtonState.StylusPrimary))
+            {
+                modifiers |= RawInputModifiers.PenBarrelButton;
+            }
+            return modifiers;
+        }
+
+#pragma warning disable CA1416 // Validate platform compatibility
+        private static RawPointerEventType GetActionType(MotionEvent e, MotionEventActions actionMasked, MotionEventToolType toolType)
+        {
+            var isTouch = toolType == MotionEventToolType.Finger;
+            var isMouse = toolType == MotionEventToolType.Mouse;
+            switch (actionMasked)
+            {
+                // DOWN
+                case MotionEventActions.Down when !isMouse:
+                case MotionEventActions.PointerDown when !isMouse:
+                    return isTouch ? RawPointerEventType.TouchBegin : RawPointerEventType.LeftButtonDown;
+                case MotionEventActions.ButtonPress:
+                    return e.ActionButton switch
+                    {
+                        MotionEventButtonState.Back => RawPointerEventType.XButton1Down,
+                        MotionEventButtonState.Forward => RawPointerEventType.XButton2Down,
+                        MotionEventButtonState.Primary => RawPointerEventType.LeftButtonDown,
+                        MotionEventButtonState.Secondary => RawPointerEventType.RightButtonDown,
+                        MotionEventButtonState.StylusPrimary => RawPointerEventType.LeftButtonDown,
+                        MotionEventButtonState.StylusSecondary => RawPointerEventType.RightButtonDown,
+                        MotionEventButtonState.Tertiary => RawPointerEventType.MiddleButtonDown,
+                        _ => RawPointerEventType.LeftButtonDown
+                    };
+                // UP
+                case MotionEventActions.Up when !isMouse:
+                case MotionEventActions.PointerUp when !isMouse:
+                    return isTouch ? RawPointerEventType.TouchEnd : RawPointerEventType.LeftButtonUp;
+                case MotionEventActions.ButtonRelease:
+                    return e.ActionButton switch
+                    {
+                        MotionEventButtonState.Back => RawPointerEventType.XButton1Up,
+                        MotionEventButtonState.Forward => RawPointerEventType.XButton2Up,
+                        MotionEventButtonState.Primary => RawPointerEventType.LeftButtonUp,
+                        MotionEventButtonState.Secondary => RawPointerEventType.RightButtonUp,
+                        MotionEventButtonState.StylusPrimary => RawPointerEventType.LeftButtonUp,
+                        MotionEventButtonState.StylusSecondary => RawPointerEventType.RightButtonUp,
+                        MotionEventButtonState.Tertiary => RawPointerEventType.MiddleButtonUp,
+                        _ => RawPointerEventType.LeftButtonUp
+                    };
+                // MOVE
+                case MotionEventActions.Outside:
+                case MotionEventActions.HoverMove:
+                case MotionEventActions.Move:
+                    return isTouch ? RawPointerEventType.TouchUpdate : RawPointerEventType.Move;
+                // CANCEL
+                case MotionEventActions.Cancel:
+                    return isTouch ? RawPointerEventType.TouchCancel : RawPointerEventType.LeaveWindow;
+                default:
+                    return (RawPointerEventType)(-1);
+            }
+        }
+#pragma warning restore CA1416 // Validate platform compatibility
+
+        private IPointerDevice GetDevice(MotionEventToolType type)
+        {
+            return type switch
+            {
+                MotionEventToolType.Mouse => _mouseDevice,
+                MotionEventToolType.Stylus => _penDevice,
+                MotionEventToolType.Eraser => _penDevice,
+                MotionEventToolType.Finger => _touchDevice,
+                _ => _touchDevice
+            };
+        }
+
+        private RawPointerPoint CreatePoint(MotionEvent e, int index)
+        {
+            return new RawPointerPoint
+            {
+                Position = new Point(e.GetX(index), e.GetY(index)) / _view.RenderScaling,
+                Pressure = Math.Min(e.GetPressure(index), 1), // android pressure can depend on the device, can be mixed up with "GetSize", may be larger than 1.0f on some devices
+                Twist = e.GetOrientation(index) * s_radiansToDegree
+            };
+        }
+
+        private RawPointerPoint CreateHistoricalPoint(MotionEvent e, int index, int pos)
+        {
+            return new RawPointerPoint
+            {
+                Position = new Point(e.GetHistoricalX(index, pos), e.GetHistoricalY(index, pos)) / _view.RenderScaling,
+                Pressure = Math.Min(e.GetHistoricalPressure(index, pos), 1),
+                Twist = e.GetHistoricalOrientation(index, pos) * s_radiansToDegree
+            };
+        }
+
+        private static RawInputModifiers GetToolModifiers(MotionEventToolType toolType)
+        {
+            // Android "Eraser" indicates Inverted pen OR actual Eraser. So we have to go both here.
+            return toolType == MotionEventToolType.Eraser ? RawInputModifiers.PenInverted | RawInputModifiers.PenEraser : RawInputModifiers.None;
+        }
+
+        public void Dispose()
+        {
+            _disposed = true;
+        }
+    }
+}

+ 0 - 85
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs

@@ -1,85 +0,0 @@
-using System;
-using Android.Views;
-using Avalonia.Input;
-using Avalonia.Input.Raw;
-using Avalonia.Platform;
-
-namespace Avalonia.Android.Platform.Specific.Helpers
-{
-    public class AndroidTouchEventsHelper<TView> : IDisposable where TView : ITopLevelImpl, IAndroidView
-    {
-        private TView _view;
-        public bool HandleEvents { get; set; }
-
-        public AndroidTouchEventsHelper(TView view, Func<IInputRoot> getInputRoot, Func<MotionEvent, int, Point> getPointfunc)
-        {
-            this._view = view;
-            HandleEvents = true;
-            _getPointFunc = getPointfunc;
-            _getInputRoot = getInputRoot;
-        }
-
-        private TouchDevice _touchDevice = new TouchDevice();
-        private Func<MotionEvent, int, Point> _getPointFunc;
-        private Func<IInputRoot> _getInputRoot;
-
-        public bool? DispatchTouchEvent(MotionEvent e, out bool callBase)
-        {
-            if (!HandleEvents)
-            {
-                callBase = true;
-                return null;
-            }
-
-            var eventTime = DateTime.Now;
-
-            //Basic touch support
-            var pointerEventType = e.Action switch
-            {
-                MotionEventActions.Down => RawPointerEventType.TouchBegin,
-                MotionEventActions.Up => RawPointerEventType.TouchEnd,
-                MotionEventActions.Cancel => RawPointerEventType.TouchCancel,
-                _ => RawPointerEventType.TouchUpdate
-            };
-
-            if (e.Action.HasFlag(MotionEventActions.PointerDown))
-            {
-                pointerEventType = RawPointerEventType.TouchBegin;
-            }
-
-            if (e.Action.HasFlag(MotionEventActions.PointerUp))
-            {
-                pointerEventType = RawPointerEventType.TouchEnd;
-            }
-
-            for (int i = 0; i < e.PointerCount; i++)
-            {
-                //if point is in view otherwise it's possible avalonia not to find the proper window to dispatch the event
-                var point = _getPointFunc(e, i);
-
-                double x = _view.View.GetX();
-                double y = _view.View.GetY();
-                double r = x + _view.View.Width;
-                double b = y + _view.View.Height;
-
-                if (x <= point.X && r >= point.X && y <= point.Y && b >= point.Y)
-                {
-                    var inputRoot = _getInputRoot();
-
-                    var mouseEvent = new RawTouchEventArgs(_touchDevice, (uint)eventTime.Ticks, inputRoot,
-                        i == e.ActionIndex ? pointerEventType : RawPointerEventType.TouchUpdate, point, RawInputModifiers.None, e.GetPointerId(i));
-                    _view.Input(mouseEvent);
-                }
-            }
-
-            callBase = true;
-            //if return false events for move and up are not received!!!
-            return e.Action != MotionEventActions.Up;
-        }
-
-        public void Dispose()
-        {
-            HandleEvents = false;
-        }
-    }
-}

+ 15 - 15
src/Avalonia.Base/Input/PointerPoint.cs

@@ -5,7 +5,7 @@ namespace Avalonia.Input
     /// <summary>
     /// Provides basic properties for the input pointer associated with a single mouse, pen/stylus, or touch contact.
     /// </summary>
-    public sealed class PointerPoint
+    public struct PointerPoint
     {
         public PointerPoint(IPointer pointer, Point position, PointerPointProperties properties)
         {
@@ -33,47 +33,47 @@ namespace Avalonia.Input
     /// <summary>
     /// Provides extended properties for a PointerPoint object.
     /// </summary>
-    public sealed class PointerPointProperties
+    public struct PointerPointProperties
     {
         /// <summary>
         /// Gets a value that indicates whether the pointer input was triggered by the primary action mode of an input device.
         /// </summary>
-        public bool IsLeftButtonPressed { get; }
+        public bool IsLeftButtonPressed { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the pointer input was triggered by the tertiary action mode of an input device.
         /// </summary>
-        public bool IsMiddleButtonPressed { get; }
+        public bool IsMiddleButtonPressed { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the pointer input was triggered by the secondary action mode (if supported) of an input device.
         /// </summary>
-        public bool IsRightButtonPressed { get; }
+        public bool IsRightButtonPressed { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the pointer input was triggered by the first extended mouse button (XButton1).
         /// </summary>
-        public bool IsXButton1Pressed { get; }
+        public bool IsXButton1Pressed { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the pointer input was triggered by the second extended mouse button (XButton2).
         /// </summary>
-        public bool IsXButton2Pressed { get; }
+        public bool IsXButton2Pressed { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the barrel button of the pen/stylus device is pressed.
         /// </summary>
-        public bool IsBarrelButtonPressed { get; }
+        public bool IsBarrelButtonPressed { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the input is from a pen eraser.
         /// </summary>
-        public bool IsEraser { get; }
+        public bool IsEraser { get; } = false;
 
         /// <summary>
         /// Gets a value that indicates whether the digitizer pen is inverted.
         /// </summary>
-        public bool IsInverted { get; }
+        public bool IsInverted { get; } = false;
 
         /// <summary>
         /// Gets the clockwise rotation in degrees of a pen device around its own major axis (such as when the user spins the pen in their fingers).
@@ -81,7 +81,7 @@ namespace Avalonia.Input
         /// <returns>
         /// A value between 0.0 and 359.0 in degrees of rotation. The default value is 0.0.
         /// </returns>
-        public float Twist { get; }
+        public float Twist { get; } = 0.0F;
 
         /// <summary>
         /// Gets a value that indicates the force that the pointer device (typically a pen/stylus) exerts on the surface of the digitizer.
@@ -97,7 +97,7 @@ namespace Avalonia.Input
         /// <returns>
         /// The value is 0.0 when the finger or pen is perpendicular to the digitizer surface, between 0.0 and 90.0 when tilted to the right of perpendicular, and between 0.0 and -90.0 when tilted to the left of perpendicular. The default value is 0.0.
         /// </returns>
-        public float XTilt { get; }
+        public float XTilt { get; } = 0.0F;
 
         /// <summary>
         /// Gets the plane angle between the X-Z plane and the plane that contains the X axis and the axis of the input device (typically a pen/stylus).
@@ -105,14 +105,14 @@ namespace Avalonia.Input
         /// <returns>
         /// The value is 0.0 when the finger or pen is perpendicular to the digitizer surface, between 0.0 and 90.0 when tilted towards the user, and between 0.0 and -90.0 when tilted away from the user. The default value is 0.0.
         /// </returns>
-        public float YTilt { get; }
+        public float YTilt { get; } = 0.0F;
 
         /// <summary>
         /// Gets the kind of pointer state change.
         /// </summary>
-        public PointerUpdateKind PointerUpdateKind { get; }
+        public PointerUpdateKind PointerUpdateKind { get; } = PointerUpdateKind.LeftButtonPressed;
 
-        private PointerPointProperties()
+        public PointerPointProperties()
         {
         }
 

+ 4 - 0
src/Avalonia.Base/Input/Raw/RawPointerEventArgs.cs

@@ -137,9 +137,13 @@ namespace Avalonia.Input.Raw
         /// </summary>
         public Point Position { get; set; }
 
+        /// <inheritdoc cref="PointerPointProperties.Twist" />
         public float Twist { get; set; }
+        /// <inheritdoc cref="PointerPointProperties.Pressure" />
         public float Pressure { get; set; }
+        /// <inheritdoc cref="PointerPointProperties.XTilt" />
         public float XTilt { get; set; }
+        /// <inheritdoc cref="PointerPointProperties.YTilt" />
         public float YTilt { get; set; }
 
 

+ 9 - 6
src/Avalonia.Base/Media/KnownColors.cs

@@ -1,10 +1,11 @@
 using System;
 using System.Reflection;
 using System.Collections.Generic;
+using Avalonia.SourceGenerator;
 
 namespace Avalonia.Media
 {
-    internal static class KnownColors
+    internal static partial class KnownColors
     {
         private static readonly IReadOnlyDictionary<string, KnownColor> _knownColorNames;
         private static readonly IReadOnlyDictionary<uint, string> _knownColors;
@@ -12,23 +13,25 @@ namespace Avalonia.Media
         private static readonly Dictionary<KnownColor, ISolidColorBrush> _knownBrushes;
 #endif
 
+        [GenerateEnumValueDictionary()]
+        private static partial Dictionary<string, KnownColor> GetKnownColors();
+
         static KnownColors()
         {
             var knownColorNames = new Dictionary<string, KnownColor>(StringComparer.OrdinalIgnoreCase);
             var knownColors = new Dictionary<uint, string>();
 
-            foreach (var field in typeof(KnownColor).GetRuntimeFields())
+            foreach (var field in GetKnownColors())
             {
-                if (field.FieldType != typeof(KnownColor)) continue;
-                var knownColor = (KnownColor)field.GetValue(null)!;
+                var knownColor = field.Value;
                 if (knownColor == KnownColor.None) continue;
 
-                knownColorNames.Add(field.Name, knownColor);
+                knownColorNames.Add(field.Key, knownColor);
 
                 // some known colors have the same value, so use the first
                 if (!knownColors.ContainsKey((uint)knownColor))
                 {
-                    knownColors.Add((uint)knownColor, field.Name);
+                    knownColors.Add((uint)knownColor, field.Key);
                 }
             }
 

+ 14 - 1
src/Avalonia.Base/VisualTree/VisualExtensions.cs

@@ -413,7 +413,7 @@ namespace Avalonia.VisualTree
                     Index = index,
                     ZIndex = element.ZIndex,
                 })
-                .OrderBy(x => x, null)
+                .OrderBy(x => x, ZOrderElement.Comparer)
                 .Select(x => x.Element!);
         }
 
@@ -448,6 +448,19 @@ namespace Avalonia.VisualTree
             public int Index { get; set; }
             public int ZIndex { get; set; }
 
+            class ZOrderComparer : IComparer<ZOrderElement>
+            {
+                public int Compare(ZOrderElement? x, ZOrderElement? y)
+                {
+                    if (ReferenceEquals(x, y)) return 0;
+                    if (ReferenceEquals(null, y)) return 1;
+                    if (ReferenceEquals(null, x)) return -1;
+                    return x.CompareTo(y);
+                }
+            }
+
+            public static IComparer<ZOrderElement> Comparer { get; } = new ZOrderComparer();
+            
             public int CompareTo(ZOrderElement? other)
             {
                 if (other is null)

+ 1 - 0
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@@ -108,4 +108,5 @@
       <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
       <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
     </ItemGroup>
+  <Import Project="..\..\build\SourceGenerators.props" />
 </Project>

+ 0 - 10
src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs

@@ -12,9 +12,6 @@ namespace Avalonia.Collections
     {
         public virtual string PropertyPath => null;
 
-        [Obsolete("Use Direction property to read or override sorting direction.")]
-        public virtual bool Descending => Direction == ListSortDirection.Descending;
-
         public virtual ListSortDirection Direction => ListSortDirection.Ascending;
         public bool HasPropertyPath => !String.IsNullOrEmpty(PropertyPath);
         public abstract IComparer<object> Comparer { get; }
@@ -254,13 +251,6 @@ namespace Avalonia.Collections
             return new DataGridPathSortDescription(propertyPath, direction, null, culture);
         }
 
-
-        [Obsolete("Use overload taking a ListSortDirection.")]
-        public static DataGridSortDescription FromPath(string propertyPath, bool descending, CultureInfo culture = null)
-        {
-            return new DataGridPathSortDescription(propertyPath, descending ? ListSortDirection.Descending : ListSortDirection.Ascending, null, culture);
-        }
-
         public static DataGridSortDescription FromPath(string propertyPath, ListSortDirection direction, IComparer comparer)
         {
             return new DataGridPathSortDescription(propertyPath, direction, comparer, null);

+ 1 - 2
src/Avalonia.Dialogs/ManagedFileChooser.cs

@@ -36,9 +36,8 @@ namespace Avalonia.Dialogs
             if (_quickLinksRoot != null)
             {
                 var isQuickLink = _quickLinksRoot.IsLogicalAncestorOf(e.Source as Control);
-#pragma warning disable CS0618 // Type or member is obsolete
+
                 if (e.ClickCount == 2 || isQuickLink)
-#pragma warning restore CS0618 // Type or member is obsolete
                 {
                     if (model.ItemType == ManagedFileChooserItemType.File)
                     {

+ 156 - 163
src/Avalonia.X11/X11Atoms.cs

@@ -39,183 +39,176 @@ using static Avalonia.X11.XLib;
 namespace Avalonia.X11
 {
 
-    internal class X11Atoms
+    internal partial class X11Atoms
     {
         private readonly IntPtr _display;
 
         // Our atoms
-        public readonly IntPtr AnyPropertyType = (IntPtr)0;
-        public readonly IntPtr XA_PRIMARY = (IntPtr)1;
-        public readonly IntPtr XA_SECONDARY = (IntPtr)2;
-        public readonly IntPtr XA_ARC = (IntPtr)3;
-        public readonly IntPtr XA_ATOM = (IntPtr)4;
-        public readonly IntPtr XA_BITMAP = (IntPtr)5;
-        public readonly IntPtr XA_CARDINAL = (IntPtr)6;
-        public readonly IntPtr XA_COLORMAP = (IntPtr)7;
-        public readonly IntPtr XA_CURSOR = (IntPtr)8;
-        public readonly IntPtr XA_CUT_BUFFER0 = (IntPtr)9;
-        public readonly IntPtr XA_CUT_BUFFER1 = (IntPtr)10;
-        public readonly IntPtr XA_CUT_BUFFER2 = (IntPtr)11;
-        public readonly IntPtr XA_CUT_BUFFER3 = (IntPtr)12;
-        public readonly IntPtr XA_CUT_BUFFER4 = (IntPtr)13;
-        public readonly IntPtr XA_CUT_BUFFER5 = (IntPtr)14;
-        public readonly IntPtr XA_CUT_BUFFER6 = (IntPtr)15;
-        public readonly IntPtr XA_CUT_BUFFER7 = (IntPtr)16;
-        public readonly IntPtr XA_DRAWABLE = (IntPtr)17;
-        public readonly IntPtr XA_FONT = (IntPtr)18;
-        public readonly IntPtr XA_INTEGER = (IntPtr)19;
-        public readonly IntPtr XA_PIXMAP = (IntPtr)20;
-        public readonly IntPtr XA_POINT = (IntPtr)21;
-        public readonly IntPtr XA_RECTANGLE = (IntPtr)22;
-        public readonly IntPtr XA_RESOURCE_MANAGER = (IntPtr)23;
-        public readonly IntPtr XA_RGB_COLOR_MAP = (IntPtr)24;
-        public readonly IntPtr XA_RGB_BEST_MAP = (IntPtr)25;
-        public readonly IntPtr XA_RGB_BLUE_MAP = (IntPtr)26;
-        public readonly IntPtr XA_RGB_DEFAULT_MAP = (IntPtr)27;
-        public readonly IntPtr XA_RGB_GRAY_MAP = (IntPtr)28;
-        public readonly IntPtr XA_RGB_GREEN_MAP = (IntPtr)29;
-        public readonly IntPtr XA_RGB_RED_MAP = (IntPtr)30;
-        public readonly IntPtr XA_STRING = (IntPtr)31;
-        public readonly IntPtr XA_VISUALID = (IntPtr)32;
-        public readonly IntPtr XA_WINDOW = (IntPtr)33;
-        public readonly IntPtr XA_WM_COMMAND = (IntPtr)34;
-        public readonly IntPtr XA_WM_HINTS = (IntPtr)35;
-        public readonly IntPtr XA_WM_CLIENT_MACHINE = (IntPtr)36;
-        public readonly IntPtr XA_WM_ICON_NAME = (IntPtr)37;
-        public readonly IntPtr XA_WM_ICON_SIZE = (IntPtr)38;
-        public readonly IntPtr XA_WM_NAME = (IntPtr)39;
-        public readonly IntPtr XA_WM_NORMAL_HINTS = (IntPtr)40;
-        public readonly IntPtr XA_WM_SIZE_HINTS = (IntPtr)41;
-        public readonly IntPtr XA_WM_ZOOM_HINTS = (IntPtr)42;
-        public readonly IntPtr XA_MIN_SPACE = (IntPtr)43;
-        public readonly IntPtr XA_NORM_SPACE = (IntPtr)44;
-        public readonly IntPtr XA_MAX_SPACE = (IntPtr)45;
-        public readonly IntPtr XA_END_SPACE = (IntPtr)46;
-        public readonly IntPtr XA_SUPERSCRIPT_X = (IntPtr)47;
-        public readonly IntPtr XA_SUPERSCRIPT_Y = (IntPtr)48;
-        public readonly IntPtr XA_SUBSCRIPT_X = (IntPtr)49;
-        public readonly IntPtr XA_SUBSCRIPT_Y = (IntPtr)50;
-        public readonly IntPtr XA_UNDERLINE_POSITION = (IntPtr)51;
-        public readonly IntPtr XA_UNDERLINE_THICKNESS = (IntPtr)52;
-        public readonly IntPtr XA_STRIKEOUT_ASCENT = (IntPtr)53;
-        public readonly IntPtr XA_STRIKEOUT_DESCENT = (IntPtr)54;
-        public readonly IntPtr XA_ITALIC_ANGLE = (IntPtr)55;
-        public readonly IntPtr XA_X_HEIGHT = (IntPtr)56;
-        public readonly IntPtr XA_QUAD_WIDTH = (IntPtr)57;
-        public readonly IntPtr XA_WEIGHT = (IntPtr)58;
-        public readonly IntPtr XA_POINT_SIZE = (IntPtr)59;
-        public readonly IntPtr XA_RESOLUTION = (IntPtr)60;
-        public readonly IntPtr XA_COPYRIGHT = (IntPtr)61;
-        public readonly IntPtr XA_NOTICE = (IntPtr)62;
-        public readonly IntPtr XA_FONT_NAME = (IntPtr)63;
-        public readonly IntPtr XA_FAMILY_NAME = (IntPtr)64;
-        public readonly IntPtr XA_FULL_NAME = (IntPtr)65;
-        public readonly IntPtr XA_CAP_HEIGHT = (IntPtr)66;
-        public readonly IntPtr XA_WM_CLASS = (IntPtr)67;
-        public readonly IntPtr XA_WM_TRANSIENT_FOR = (IntPtr)68;
+        public IntPtr AnyPropertyType = (IntPtr)0;
+        public IntPtr XA_PRIMARY = (IntPtr)1;
+        public IntPtr XA_SECONDARY = (IntPtr)2;
+        public IntPtr XA_ARC = (IntPtr)3;
+        public IntPtr XA_ATOM = (IntPtr)4;
+        public IntPtr XA_BITMAP = (IntPtr)5;
+        public IntPtr XA_CARDINAL = (IntPtr)6;
+        public IntPtr XA_COLORMAP = (IntPtr)7;
+        public IntPtr XA_CURSOR = (IntPtr)8;
+        public IntPtr XA_CUT_BUFFER0 = (IntPtr)9;
+        public IntPtr XA_CUT_BUFFER1 = (IntPtr)10;
+        public IntPtr XA_CUT_BUFFER2 = (IntPtr)11;
+        public IntPtr XA_CUT_BUFFER3 = (IntPtr)12;
+        public IntPtr XA_CUT_BUFFER4 = (IntPtr)13;
+        public IntPtr XA_CUT_BUFFER5 = (IntPtr)14;
+        public IntPtr XA_CUT_BUFFER6 = (IntPtr)15;
+        public IntPtr XA_CUT_BUFFER7 = (IntPtr)16;
+        public IntPtr XA_DRAWABLE = (IntPtr)17;
+        public IntPtr XA_FONT = (IntPtr)18;
+        public IntPtr XA_INTEGER = (IntPtr)19;
+        public IntPtr XA_PIXMAP = (IntPtr)20;
+        public IntPtr XA_POINT = (IntPtr)21;
+        public IntPtr XA_RECTANGLE = (IntPtr)22;
+        public IntPtr XA_RESOURCE_MANAGER = (IntPtr)23;
+        public IntPtr XA_RGB_COLOR_MAP = (IntPtr)24;
+        public IntPtr XA_RGB_BEST_MAP = (IntPtr)25;
+        public IntPtr XA_RGB_BLUE_MAP = (IntPtr)26;
+        public IntPtr XA_RGB_DEFAULT_MAP = (IntPtr)27;
+        public IntPtr XA_RGB_GRAY_MAP = (IntPtr)28;
+        public IntPtr XA_RGB_GREEN_MAP = (IntPtr)29;
+        public IntPtr XA_RGB_RED_MAP = (IntPtr)30;
+        public IntPtr XA_STRING = (IntPtr)31;
+        public IntPtr XA_VISUALID = (IntPtr)32;
+        public IntPtr XA_WINDOW = (IntPtr)33;
+        public IntPtr XA_WM_COMMAND = (IntPtr)34;
+        public IntPtr XA_WM_HINTS = (IntPtr)35;
+        public IntPtr XA_WM_CLIENT_MACHINE = (IntPtr)36;
+        public IntPtr XA_WM_ICON_NAME = (IntPtr)37;
+        public IntPtr XA_WM_ICON_SIZE = (IntPtr)38;
+        public IntPtr XA_WM_NAME = (IntPtr)39;
+        public IntPtr XA_WM_NORMAL_HINTS = (IntPtr)40;
+        public IntPtr XA_WM_SIZE_HINTS = (IntPtr)41;
+        public IntPtr XA_WM_ZOOM_HINTS = (IntPtr)42;
+        public IntPtr XA_MIN_SPACE = (IntPtr)43;
+        public IntPtr XA_NORM_SPACE = (IntPtr)44;
+        public IntPtr XA_MAX_SPACE = (IntPtr)45;
+        public IntPtr XA_END_SPACE = (IntPtr)46;
+        public IntPtr XA_SUPERSCRIPT_X = (IntPtr)47;
+        public IntPtr XA_SUPERSCRIPT_Y = (IntPtr)48;
+        public IntPtr XA_SUBSCRIPT_X = (IntPtr)49;
+        public IntPtr XA_SUBSCRIPT_Y = (IntPtr)50;
+        public IntPtr XA_UNDERLINE_POSITION = (IntPtr)51;
+        public IntPtr XA_UNDERLINE_THICKNESS = (IntPtr)52;
+        public IntPtr XA_STRIKEOUT_ASCENT = (IntPtr)53;
+        public IntPtr XA_STRIKEOUT_DESCENT = (IntPtr)54;
+        public IntPtr XA_ITALIC_ANGLE = (IntPtr)55;
+        public IntPtr XA_X_HEIGHT = (IntPtr)56;
+        public IntPtr XA_QUAD_WIDTH = (IntPtr)57;
+        public IntPtr XA_WEIGHT = (IntPtr)58;
+        public IntPtr XA_POINT_SIZE = (IntPtr)59;
+        public IntPtr XA_RESOLUTION = (IntPtr)60;
+        public IntPtr XA_COPYRIGHT = (IntPtr)61;
+        public IntPtr XA_NOTICE = (IntPtr)62;
+        public IntPtr XA_FONT_NAME = (IntPtr)63;
+        public IntPtr XA_FAMILY_NAME = (IntPtr)64;
+        public IntPtr XA_FULL_NAME = (IntPtr)65;
+        public IntPtr XA_CAP_HEIGHT = (IntPtr)66;
+        public IntPtr XA_WM_CLASS = (IntPtr)67;
+        public IntPtr XA_WM_TRANSIENT_FOR = (IntPtr)68;
 
-        public readonly IntPtr EDID;
+        public IntPtr EDID;
 
-        public readonly IntPtr WM_PROTOCOLS;
-        public readonly IntPtr WM_DELETE_WINDOW;
-        public readonly IntPtr WM_TAKE_FOCUS;
-        public readonly IntPtr _NET_SUPPORTED;
-        public readonly IntPtr _NET_CLIENT_LIST;
-        public readonly IntPtr _NET_NUMBER_OF_DESKTOPS;
-        public readonly IntPtr _NET_DESKTOP_GEOMETRY;
-        public readonly IntPtr _NET_DESKTOP_VIEWPORT;
-        public readonly IntPtr _NET_CURRENT_DESKTOP;
-        public readonly IntPtr _NET_DESKTOP_NAMES;
-        public readonly IntPtr _NET_ACTIVE_WINDOW;
-        public readonly IntPtr _NET_WORKAREA;
-        public readonly IntPtr _NET_SUPPORTING_WM_CHECK;
-        public readonly IntPtr _NET_VIRTUAL_ROOTS;
-        public readonly IntPtr _NET_DESKTOP_LAYOUT;
-        public readonly IntPtr _NET_SHOWING_DESKTOP;
-        public readonly IntPtr _NET_CLOSE_WINDOW;
-        public readonly IntPtr _NET_MOVERESIZE_WINDOW;
-        public readonly IntPtr _NET_WM_MOVERESIZE;
-        public readonly IntPtr _NET_RESTACK_WINDOW;
-        public readonly IntPtr _NET_REQUEST_FRAME_EXTENTS;
-        public readonly IntPtr _NET_WM_NAME;
-        public readonly IntPtr _NET_WM_VISIBLE_NAME;
-        public readonly IntPtr _NET_WM_ICON_NAME;
-        public readonly IntPtr _NET_WM_VISIBLE_ICON_NAME;
-        public readonly IntPtr _NET_WM_DESKTOP;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE;
-        public readonly IntPtr _NET_WM_STATE;
-        public readonly IntPtr _NET_WM_ALLOWED_ACTIONS;
-        public readonly IntPtr _NET_WM_STRUT;
-        public readonly IntPtr _NET_WM_STRUT_PARTIAL;
-        public readonly IntPtr _NET_WM_ICON_GEOMETRY;
-        public readonly IntPtr _NET_WM_ICON;
-        public readonly IntPtr _NET_WM_PID;
-        public readonly IntPtr _NET_WM_HANDLED_ICONS;
-        public readonly IntPtr _NET_WM_USER_TIME;
-        public readonly IntPtr _NET_FRAME_EXTENTS;
-        public readonly IntPtr _NET_WM_PING;
-        public readonly IntPtr _NET_WM_SYNC_REQUEST;
-        public readonly IntPtr _NET_WM_SYNC_REQUEST_COUNTER;
-        public readonly IntPtr _NET_SYSTEM_TRAY_S;
-        public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
-        public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE;
-        public readonly IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
-        public readonly IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
-        public readonly IntPtr _NET_WM_STATE_FULLSCREEN;
-        public readonly IntPtr _XEMBED;
-        public readonly IntPtr _XEMBED_INFO;
-        public readonly IntPtr _MOTIF_WM_HINTS;
-        public readonly IntPtr _NET_WM_STATE_SKIP_TASKBAR;
-        public readonly IntPtr _NET_WM_STATE_ABOVE;
-        public readonly IntPtr _NET_WM_STATE_MODAL;
-        public readonly IntPtr _NET_WM_STATE_HIDDEN;
-        public readonly IntPtr _NET_WM_CONTEXT_HELP;
-        public readonly IntPtr _NET_WM_WINDOW_OPACITY;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_DOCK;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_MENU;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
-        public readonly IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
-        public readonly IntPtr CLIPBOARD;
-        public readonly IntPtr CLIPBOARD_MANAGER;
-        public readonly IntPtr SAVE_TARGETS;
-        public readonly IntPtr MULTIPLE;
-        public readonly IntPtr PRIMARY;
-        public readonly IntPtr OEMTEXT;
-        public readonly IntPtr UNICODETEXT;
-        public readonly IntPtr TARGETS;
-        public readonly IntPtr UTF8_STRING;
-        public readonly IntPtr UTF16_STRING;
-        public readonly IntPtr ATOM_PAIR;
-        public readonly IntPtr MANAGER;
-        public readonly IntPtr _KDE_NET_WM_BLUR_BEHIND_REGION;
-        public readonly IntPtr INCR;
+        public IntPtr WM_PROTOCOLS;
+        public IntPtr WM_DELETE_WINDOW;
+        public IntPtr WM_TAKE_FOCUS;
+        public IntPtr _NET_SUPPORTED;
+        public IntPtr _NET_CLIENT_LIST;
+        public IntPtr _NET_NUMBER_OF_DESKTOPS;
+        public IntPtr _NET_DESKTOP_GEOMETRY;
+        public IntPtr _NET_DESKTOP_VIEWPORT;
+        public IntPtr _NET_CURRENT_DESKTOP;
+        public IntPtr _NET_DESKTOP_NAMES;
+        public IntPtr _NET_ACTIVE_WINDOW;
+        public IntPtr _NET_WORKAREA;
+        public IntPtr _NET_SUPPORTING_WM_CHECK;
+        public IntPtr _NET_VIRTUAL_ROOTS;
+        public IntPtr _NET_DESKTOP_LAYOUT;
+        public IntPtr _NET_SHOWING_DESKTOP;
+        public IntPtr _NET_CLOSE_WINDOW;
+        public IntPtr _NET_MOVERESIZE_WINDOW;
+        public IntPtr _NET_WM_MOVERESIZE;
+        public IntPtr _NET_RESTACK_WINDOW;
+        public IntPtr _NET_REQUEST_FRAME_EXTENTS;
+        public IntPtr _NET_WM_NAME;
+        public IntPtr _NET_WM_VISIBLE_NAME;
+        public IntPtr _NET_WM_ICON_NAME;
+        public IntPtr _NET_WM_VISIBLE_ICON_NAME;
+        public IntPtr _NET_WM_DESKTOP;
+        public IntPtr _NET_WM_WINDOW_TYPE;
+        public IntPtr _NET_WM_STATE;
+        public IntPtr _NET_WM_ALLOWED_ACTIONS;
+        public IntPtr _NET_WM_STRUT;
+        public IntPtr _NET_WM_STRUT_PARTIAL;
+        public IntPtr _NET_WM_ICON_GEOMETRY;
+        public IntPtr _NET_WM_ICON;
+        public IntPtr _NET_WM_PID;
+        public IntPtr _NET_WM_HANDLED_ICONS;
+        public IntPtr _NET_WM_USER_TIME;
+        public IntPtr _NET_FRAME_EXTENTS;
+        public IntPtr _NET_WM_PING;
+        public IntPtr _NET_WM_SYNC_REQUEST;
+        public IntPtr _NET_WM_SYNC_REQUEST_COUNTER;
+        public IntPtr _NET_SYSTEM_TRAY_S;
+        public IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
+        public IntPtr _NET_SYSTEM_TRAY_OPCODE;
+        public IntPtr _NET_WM_STATE_MAXIMIZED_HORZ;
+        public IntPtr _NET_WM_STATE_MAXIMIZED_VERT;
+        public IntPtr _NET_WM_STATE_FULLSCREEN;
+        public IntPtr _XEMBED;
+        public IntPtr _XEMBED_INFO;
+        public IntPtr _MOTIF_WM_HINTS;
+        public IntPtr _NET_WM_STATE_SKIP_TASKBAR;
+        public IntPtr _NET_WM_STATE_ABOVE;
+        public IntPtr _NET_WM_STATE_MODAL;
+        public IntPtr _NET_WM_STATE_HIDDEN;
+        public IntPtr _NET_WM_CONTEXT_HELP;
+        public IntPtr _NET_WM_WINDOW_OPACITY;
+        public IntPtr _NET_WM_WINDOW_TYPE_DESKTOP;
+        public IntPtr _NET_WM_WINDOW_TYPE_DOCK;
+        public IntPtr _NET_WM_WINDOW_TYPE_TOOLBAR;
+        public IntPtr _NET_WM_WINDOW_TYPE_MENU;
+        public IntPtr _NET_WM_WINDOW_TYPE_UTILITY;
+        public IntPtr _NET_WM_WINDOW_TYPE_SPLASH;
+        public IntPtr _NET_WM_WINDOW_TYPE_DIALOG;
+        public IntPtr _NET_WM_WINDOW_TYPE_NORMAL;
+        public IntPtr CLIPBOARD;
+        public IntPtr CLIPBOARD_MANAGER;
+        public IntPtr SAVE_TARGETS;
+        public IntPtr MULTIPLE;
+        public IntPtr PRIMARY;
+        public IntPtr OEMTEXT;
+        public IntPtr UNICODETEXT;
+        public IntPtr TARGETS;
+        public IntPtr UTF8_STRING;
+        public IntPtr UTF16_STRING;
+        public IntPtr ATOM_PAIR;
+        public IntPtr MANAGER;
+        public IntPtr _KDE_NET_WM_BLUR_BEHIND_REGION;
+        public IntPtr INCR;
 
         private readonly Dictionary<string, IntPtr> _namesToAtoms  = new Dictionary<string, IntPtr>();
         private readonly Dictionary<IntPtr, string> _atomsToNames = new Dictionary<IntPtr, string>();
         public X11Atoms(IntPtr display)
         {
             _display = display;
+            PopulateAtoms(display);
+        }
 
-            // make sure this array stays in sync with the statements below
-
-            var fields = typeof(X11Atoms).GetFields()
-                .Where(f => f.FieldType == typeof(IntPtr) && (IntPtr)f.GetValue(this) == IntPtr.Zero).ToArray();
-            var atomNames = fields.Select(f => f.Name).ToArray();
-
-            IntPtr[] atoms = new IntPtr [atomNames.Length];
-            ;
-
-            XInternAtoms(display, atomNames, atomNames.Length, true, atoms);
-
-            for (var c = 0; c < fields.Length; c++)
+        private void InitAtom(ref IntPtr field, string name, IntPtr value)
+        {
+            if (value != IntPtr.Zero)
             {
-                _namesToAtoms[fields[c].Name] = atoms[c];
-                _atomsToNames[atoms[c]] = fields[c].Name;
-                fields[c].SetValue(this, atoms[c]);
+                field = value;
+                _namesToAtoms[name] = value;
+                _atomsToNames[value] = name;
             }
         }
 

+ 6 - 2
src/Avalonia.X11/X11CursorFactory.cs

@@ -5,13 +5,14 @@ using System.Runtime.InteropServices;
 using Avalonia.Controls.Platform.Surfaces;
 using Avalonia.Input;
 using Avalonia.Platform;
+using Avalonia.SourceGenerator;
 using Avalonia.Utilities;
 
 #nullable enable
 
 namespace Avalonia.X11
 {
-    class X11CursorFactory : ICursorFactory
+    partial class X11CursorFactory : ICursorFactory
     {
         private static readonly byte[] NullCursorData = new byte[] { 0 };
 
@@ -48,11 +49,14 @@ namespace Avalonia.X11
                 {StandardCursorType.TopRightCorner, CursorFontShape.XC_top_right_corner},
             };
 
+        [GenerateEnumValueList]
+        private static partial CursorFontShape[] GetAllCursorShapes();
+        
         public X11CursorFactory(IntPtr display)
         {
             _display = display;
             _nullCursor = GetNullCursor(display);
-            _cursors = Enum.GetValues(typeof(CursorFontShape)).Cast<CursorFontShape>()
+            _cursors = GetAllCursorShapes()
                 .ToDictionary(id => id, id => XLib.XCreateFontCursor(_display, id));
         }
 

+ 14 - 1
src/Avalonia.X11/X11Platform.cs

@@ -278,7 +278,8 @@ namespace Avalonia
             "llvmpipe"
         };
 
-        public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name;
+        
+        public string WmClass { get; set; }
 
         /// <summary>
         /// Enables multitouch support. The default value is true.
@@ -287,6 +288,18 @@ namespace Avalonia
         /// Multitouch allows a surface (a touchpad or touchscreen) to recognize the presence of more than one point of contact with the surface at the same time.
         /// </remarks>
         public bool? EnableMultiTouch { get; set; } = true;
+
+        public X11PlatformOptions()
+        {
+            try
+            {
+                WmClass = Assembly.GetEntryAssembly()?.GetName()?.Name;
+            }
+            catch
+            {
+                //
+            }
+        }
     }
     public static class AvaloniaX11PlatformExtensions
     {

+ 0 - 3
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@@ -158,9 +158,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
                     string.Join(",", lst.Select(e => $"`{e.ClrAssemblyName}:{e.ClrNamespace}.{name}`")));
             }
         }
-        
-        [Obsolete("Don't use", true)]
-        public static readonly IServiceProvider RootServiceProviderV1 = new RootServiceProvider(null);
 
         // Don't emit debug symbols for this code so debugger will be forced to step into XAML instead
         #line hidden

+ 8 - 0
src/Shared/SourceGeneratorAttributes.cs

@@ -38,4 +38,12 @@ namespace Avalonia.SourceGenerator
 
         }
     }
+
+    internal class GenerateEnumValueDictionaryAttribute : Attribute
+    {
+    }
+    
+    internal class GenerateEnumValueListAttribute : Attribute
+    {
+    }
 }

+ 1 - 69
src/Skia/Avalonia.Skia/Helpers/DrawingContextHelper.cs

@@ -1,5 +1,4 @@
-using System;
-using Avalonia.Platform;
+using Avalonia.Platform;
 using Avalonia.Rendering;
 using SkiaSharp;
 
@@ -29,72 +28,5 @@ namespace Avalonia.Skia.Helpers
             return new DrawingContextImpl(createInfo);
         }
         
-        /// <summary>
-        /// Unsupported - Wraps a GPU Backed SkiaSurface in an Avalonia DrawingContext.
-        /// </summary>
-        [Obsolete]
-        public static IDrawingContextImpl WrapSkiaSurface(this SKSurface surface, GRContext grContext, Vector dpi, params IDisposable[] disposables)
-        {
-            var createInfo = new DrawingContextImpl.CreateInfo
-            {
-                GrContext = grContext,
-                Surface = surface,
-                Dpi = dpi,
-                DisableTextLcdRendering = false,
-            };
-
-            return new DrawingContextImpl(createInfo, disposables);
-        }
-        
-        /// <summary>
-        /// Unsupported - Wraps a non-GPU Backed SkiaSurface in an Avalonia DrawingContext.
-        /// </summary>
-        [Obsolete]
-        public static IDrawingContextImpl WrapSkiaSurface(this SKSurface surface, Vector dpi, params IDisposable[] disposables)
-        {
-            var createInfo = new DrawingContextImpl.CreateInfo
-            {
-                Surface = surface,
-                Dpi = dpi,
-                DisableTextLcdRendering = false,
-            };
-
-            return new DrawingContextImpl(createInfo, disposables);
-        }
-
-        [Obsolete]
-        public static IDrawingContextImpl CreateDrawingContext(Size size, Vector dpi, GRContext grContext = null)
-        {
-            if (grContext is null)
-            {
-                var surface = SKSurface.Create(
-                    new SKImageInfo(
-                        (int)Math.Ceiling(size.Width),
-                        (int)Math.Ceiling(size.Height),
-                        SKImageInfo.PlatformColorType,
-                        SKAlphaType.Premul));
-
-                return WrapSkiaSurface(surface, dpi, surface);
-            }
-            else
-            {
-                var surface = SKSurface.Create(grContext, false,
-                    new SKImageInfo(
-                        (int)Math.Ceiling(size.Width),
-                        (int)Math.Ceiling(size.Height),
-                        SKImageInfo.PlatformColorType,
-                        SKAlphaType.Premul));
-
-                return WrapSkiaSurface(surface, grContext, dpi, surface);
-            }
-        }
-        
-        [Obsolete]
-        public static void DrawTo(this IDrawingContextImpl source, IDrawingContextImpl destination, SKPaint paint = null)
-        {
-            var src = (DrawingContextImpl)source;
-            var dst = (DrawingContextImpl)destination;
-            dst.Canvas.DrawSurface(src.Surface, new SKPoint(0, 0), paint);
-        }
     }
 }

+ 0 - 9
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -65,15 +65,6 @@ namespace Avalonia
             "Microsoft Basic Render"
         };
 
-        /// <summary>
-        /// Enables multitouch support. The default value is true.
-        /// </summary>
-        /// <remarks>
-        /// Multitouch allows a surface (a touchpad or touchscreen) to recognize the presence of more than one point of contact with the surface at the same time.
-        /// </remarks>
-        [Obsolete("Multitouch is always enabled on supported Windows versions")]
-        public bool? EnableMultitouch { get; set; } = true;
-
         /// <summary>
         /// Embeds popups to the window when set to true. The default value is false.
         /// </summary>

+ 94 - 0
src/tools/DevGenerators/EnumMemberDictionaryGenerator.cs

@@ -0,0 +1,94 @@
+using System.IO;
+using System.Linq;
+using System.Text;
+using Generator;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace DevGenerators;
+
+[Generator(LanguageNames.CSharp)]
+public class EnumMemberDictionaryGenerator : IIncrementalGenerator
+{
+    const string DictionaryAttributeFullName = "global::Avalonia.SourceGenerator.GenerateEnumValueDictionaryAttribute";
+    const string ListAttributeFullName = "global::Avalonia.SourceGenerator.GenerateEnumValueListAttribute";
+    
+    public void Initialize(IncrementalGeneratorInitializationContext context)
+    {
+        var allMethodsWithAttributes = context.SyntaxProvider
+            .CreateSyntaxProvider(
+                static (s, _) => s is MethodDeclarationSyntax
+                {
+                    AttributeLists.Count: > 0,
+                } md && md.Modifiers.Any(m=>m.IsKind(SyntaxKind.PartialKeyword)),
+                static (context, _) =>
+                    (IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
+
+        var all = allMethodsWithAttributes
+            .Where(s =>
+                s.HasAttributeWithFullyQualifiedName(DictionaryAttributeFullName)
+                || s.HasAttributeWithFullyQualifiedName(ListAttributeFullName)
+            ).Collect();
+        context.RegisterSourceOutput(all, static (context, methods) =>
+        {
+            foreach (var typeGroup in methods.GroupBy(f => f.ContainingType))
+            {
+                var classBuilder = new StringBuilder();
+                if (typeGroup.Key.ContainingNamespace != null)
+                    classBuilder
+                        .AppendLine("using System;")
+                        .Append("namespace ")
+                        .Append(typeGroup.Key.ContainingNamespace)
+                        .AppendLine(";");
+                classBuilder
+                    .Append("partial class ")
+                    .AppendLine(typeGroup.Key.Name)
+                    .AppendLine("{");
+
+                foreach (var method in typeGroup)
+                {
+                    var namedReturn = method.ReturnType as INamedTypeSymbol;
+                    var arrayReturn = method.ReturnType as IArrayTypeSymbol;
+                    
+                    if ((namedReturn != null && namedReturn.Arity > 0) || arrayReturn != null)
+                    {
+                        ITypeSymbol enumType = namedReturn != null
+                            ? namedReturn.TypeArguments.Last()
+                            : arrayReturn!.ElementType;
+
+                        var isDic = method.HasAttributeWithFullyQualifiedName(DictionaryAttributeFullName);
+
+                        classBuilder
+                            .Pad(1)
+                            .Append("private static partial " + method.ReturnType + " " + method.Name + "()")
+                            .AppendLine().Pad(4).Append(" => new ").Append(method.ReturnType).AppendLine("{");
+                        foreach (var member in enumType.GetMembers())
+                        {
+                            if (member.Name == ".ctor")
+                                continue;
+
+                            if (isDic)
+                                classBuilder.Pad(2)
+                                    .Append("{\"")
+                                    .Append(member.Name)
+                                    .Append("\", ")
+                                    .Append(member.ToString())
+                                    .AppendLine("},");
+                            else
+                                classBuilder.Pad(2).Append(member.ToString()).AppendLine(",");
+                        }
+
+                        classBuilder.Pad(1).AppendLine("};");
+                    }
+                }
+                classBuilder.AppendLine("}");
+
+                context.AddSource(typeGroup.Key.GetFullyQualifiedName().Replace(":", ""), classBuilder.ToString());
+            }
+        });
+
+        
+    }
+
+}

+ 73 - 0
src/tools/DevGenerators/X11AtomsGenerator.cs

@@ -0,0 +1,73 @@
+using System.IO;
+using System.Linq;
+using System.Text;
+using Generator;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace DevGenerators;
+
+[Generator(LanguageNames.CSharp)]
+public class X11AtomsGenerator : IIncrementalGenerator
+{
+    public void Initialize(IncrementalGeneratorInitializationContext context)
+    {
+        var x11AtomsClasses = context.SyntaxProvider
+            .CreateSyntaxProvider(
+                static (s, _) => s is ClassDeclarationSyntax
+                {
+                    Identifier.Text: "X11Atoms"
+                },
+                static (context, _) =>
+                    (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
+
+        var all = x11AtomsClasses.Collect();
+        context.RegisterSourceOutput(all, static (context, classes) =>
+        {
+            foreach (var cl in classes)
+            {
+                var classBuilder = new StringBuilder();
+                if (cl.ContainingNamespace != null)
+                    classBuilder
+                        .AppendLine("using System;")
+                        .AppendLine("using static Avalonia.X11.XLib;")
+                        .Append("namespace ")
+                        .Append(cl.ContainingNamespace)
+                        .AppendLine(";");
+                classBuilder
+                    .Append("partial class ")
+                    .AppendLine(cl.Name)
+                    .AppendLine("{");
+
+                var fields = cl.GetMembers().OfType<IFieldSymbol>()
+                    .Where(f => f.Type.Name == "IntPtr"
+                                && f.DeclaredAccessibility == Accessibility.Public).ToList();
+                
+                classBuilder.Pad(1).AppendLine("private void PopulateAtoms(IntPtr display)").Pad(1).AppendLine("{");
+                classBuilder.Pad(2).Append("var atoms = new IntPtr[").Append(fields.Count).AppendLine("];");
+                classBuilder.Pad(2).Append("var atomNames = new string[").Append(fields.Count).AppendLine("] {");
+
+
+                for (int c = 0; c < fields.Count; c++)
+                    classBuilder.Pad(3).Append("\"").Append(fields[c].Name).AppendLine("\",");
+                classBuilder.Pad(2).AppendLine("};");
+                
+                classBuilder.Pad(2).AppendLine("XInternAtoms(display, atomNames, atomNames.Length, true, atoms);");
+
+                for (int c = 0; c < fields.Count; c++)
+                    classBuilder.Pad(2).Append("InitAtom(ref ").Append(fields[c].Name).Append(", \"")
+                        .Append(fields[c].Name).Append("\", atoms[").Append(c).AppendLine("]);");
+
+
+                classBuilder.Pad(1).AppendLine("}");
+                classBuilder.AppendLine("}");
+
+                context.AddSource(cl.GetFullyQualifiedName().Replace(":", ""), classBuilder.ToString());
+            }
+        });
+
+        
+    }
+
+}