diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 903f9e3843..a3bbc33418 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -35,9 +35,9 @@ jobs: version: 6.0.401 - task: UseDotNet@2 - displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23' + displayName: 'Use .NET Core SDK 7.0' inputs: - version: 7.0.100-rc.2.22477.23 + version: 7.0.100 - task: CmdLine@2 displayName: 'Install Workloads' @@ -72,9 +72,9 @@ jobs: version: 6.0.401 - task: UseDotNet@2 - displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23' + displayName: 'Use .NET Core SDK 7.0.100' inputs: - version: 7.0.100-rc.2.22477.23 + version: 7.0.100 - task: CmdLine@2 displayName: 'Install Workloads' @@ -143,9 +143,9 @@ jobs: version: 6.0.401 - task: UseDotNet@2 - displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23' + displayName: 'Use .NET Core SDK 7.0.100' inputs: - version: 7.0.100-rc.2.22477.23 + version: 7.0.100 - task: CmdLine@2 displayName: 'Install Workloads' diff --git a/global.json b/global.json index dc6da556b3..a9318b212f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.100-rc.2.22477.23", + "version": "7.0.100", "rollForward": "latestFeature" }, "msbuild-sdks": { diff --git a/native/Avalonia.Native/src/OSX/rendertarget.mm b/native/Avalonia.Native/src/OSX/rendertarget.mm index 2075cc85ab..1c22c91207 100644 --- a/native/Avalonia.Native/src/OSX/rendertarget.mm +++ b/native/Avalonia.Native/src/OSX/rendertarget.mm @@ -183,8 +183,11 @@ static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* ta [_layer setContents: (__bridge IOSurface*) surface->surface]; } [CATransaction commit]; - [CATransaction flush]; } + // This can trigger event processing on the main thread + // which might need to lock the renderer + // which can cause a deadlock. So flush call is outside of the lock + [CATransaction flush]; } else dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 7425c344c3..2295c0beda 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -145,8 +145,25 @@ partial class Build : NukeBuild { Information($"Running tests from {projectName}"); var project = Solution.GetProject(projectName).NotNull("project != null"); + // Nuke and MSBuild tools have build-in helpers to get target frameworks from the project. + // Unfortunately, it gets broken with every second SDK update, so we had to do it manually. + var fileXml = XDocument.Parse(File.ReadAllText(project.Path)); + var targetFrameworks = fileXml.Descendants("TargetFrameworks") + .FirstOrDefault()?.Value.Split(';').Select(f => f.Trim()); + if (targetFrameworks is null) + { + var targetFramework = fileXml.Descendants("TargetFramework").FirstOrDefault()?.Value; + if (targetFramework is not null) + { + targetFrameworks = new[] { targetFramework }; + } + } + if (targetFrameworks is null) + { + throw new InvalidOperationException("No target frameworks were found in the test project"); + } - foreach (var fw in project.GetTargetFrameworks()) + foreach (var fw in targetFrameworks) { if (fw.StartsWith("net4") && RuntimeInformation.IsOSPlatform(OSPlatform.Linux) diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 865d935ad7..92d9732e91 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -16,8 +16,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 984eb775b5..4e972d504a 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -165,6 +165,28 @@ namespace Avalonia.Android.Platform.SkiaPlatform _tl.Draw(); } + protected override void DispatchDraw(global::Android.Graphics.Canvas canvas) + { + // Workaround issue #9230 on where screen remains gray after splash screen. + // base.DispatchDraw should punch a hole into the canvas so the surface + // can be seen below, but it does not. + if (OperatingSystem.IsAndroidVersionAtLeast(29)) + { + // Android 10+ does this (BlendMode was new) + var paint = new Paint(); + paint.SetColor(0); + paint.BlendMode = BlendMode.Clear; + canvas.DrawRect(0, 0, Width, Height, paint); + } + else + { + // Android 9 did this + canvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear); + } + + base.DispatchDraw(canvas); + } + protected override bool DispatchGenericPointerEvent(MotionEvent e) { bool callBase; diff --git a/src/Avalonia.Base/Layout/UniformGridLayoutState.cs b/src/Avalonia.Base/Layout/UniformGridLayoutState.cs index d6b5a30bfc..65cdf4c94b 100644 --- a/src/Avalonia.Base/Layout/UniformGridLayoutState.cs +++ b/src/Avalonia.Base/Layout/UniformGridLayoutState.cs @@ -117,12 +117,12 @@ namespace Avalonia.Layout double extraMinorPixelsForEachItem = 0.0; if (!double.IsInfinity(availableSizeMinor)) { - var numItemsPerColumn = Math.Min( + var numItemsPerColumn = (int)Math.Min( maxItemsPerLine, Math.Max(1.0, availableSizeMinor / (itemSizeMinor + minorItemSpacing))); var usedSpace = (numItemsPerColumn * (itemSizeMinor + minorItemSpacing)) - minorItemSpacing; - var remainingSpace = ((int)(availableSizeMinor - usedSpace)); - extraMinorPixelsForEachItem = remainingSpace / ((int)numItemsPerColumn); + var remainingSpace = availableSizeMinor - usedSpace; + extraMinorPixelsForEachItem = (int)(remainingSpace / numItemsPerColumn); } if (stretch == UniformGridLayoutItemsStretch.Fill) diff --git a/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs b/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs index 8fa7ede77e..d009926bc5 100644 --- a/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs +++ b/src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs @@ -42,6 +42,11 @@ namespace Avalonia.Controls Red800 = 0xFFC62828, Red900 = 0xFFB71C1C, + RedA100 = 0xFFFF8A80, + RedA200 = 0xFFFF5252, + RedA400 = 0xFFFF1744, + RedA700 = 0xFFD50000, + // Pink Pink50 = 0xFFFCE4EC, Pink100 = 0xFFF8BBD0, @@ -54,6 +59,11 @@ namespace Avalonia.Controls Pink800 = 0xFFAD1457, Pink900 = 0xFF880E4F, + PinkA100 = 0xFFFF80AB, + PinkA200 = 0xFFFF4081, + PinkA400 = 0xFFF50057, + PinkA700 = 0xFFC51162, + // Purple Purple50 = 0xFFF3E5F5, Purple100 = 0xFFE1BEE7, @@ -66,6 +76,11 @@ namespace Avalonia.Controls Purple800 = 0xFF6A1B9A, Purple900 = 0xFF4A148C, + PurpleA100 = 0xFFEA80FC, + PurpleA200 = 0xFFE040FB, + PurpleA400 = 0xFFD500F9, + PurpleA700 = 0xFFAA00FF, + // Deep Purple DeepPurple50 = 0xFFEDE7F6, DeepPurple100 = 0xFFD1C4E9, @@ -78,6 +93,11 @@ namespace Avalonia.Controls DeepPurple800 = 0xFF4527A0, DeepPurple900 = 0xFF311B92, + DeepPurpleA100 = 0xFFB388FF, + DeepPurpleA200 = 0xFF7C4DFF, + DeepPurpleA400 = 0xFF651FFF, + DeepPurpleA700 = 0xFF6200EA, + // Indigo Indigo50 = 0xFFE8EAF6, Indigo100 = 0xFFC5CAE9, @@ -90,6 +110,11 @@ namespace Avalonia.Controls Indigo800 = 0xFF283593, Indigo900 = 0xFF1A237E, + IndigoA100 = 0xFF8C9EFF, + IndigoA200 = 0xFF536DFE, + IndigoA400 = 0xFF3D5AFE, + IndigoA700 = 0xFF304FFE, + // Blue Blue50 = 0xFFE3F2FD, Blue100 = 0xFFBBDEFB, @@ -102,6 +127,11 @@ namespace Avalonia.Controls Blue800 = 0xFF1565C0, Blue900 = 0xFF0D47A1, + BlueA100 = 0xFF82B1FF, + BlueA200 = 0xFF448AFF, + BlueA400 = 0xFF2979FF, + BlueA700 = 0xFF2962FF, + // Light Blue LightBlue50 = 0xFFE1F5FE, LightBlue100 = 0xFFB3E5FC, @@ -114,6 +144,11 @@ namespace Avalonia.Controls LightBlue800 = 0xFF0277BD, LightBlue900 = 0xFF01579B, + LightBlueA100 = 0xFF80D8FF, + LightBlueA200 = 0xFF40C4FF, + LightBlueA400 = 0xFF00B0FF, + LightBlueA700 = 0xFF0091EA, + // Cyan Cyan50 = 0xFFE0F7FA, Cyan100 = 0xFFB2EBF2, @@ -126,6 +161,11 @@ namespace Avalonia.Controls Cyan800 = 0xFF00838F, Cyan900 = 0xFF006064, + CyanA100 = 0xFF84FFFF, + CyanA200 = 0xFF18FFFF, + CyanA400 = 0xFF00E5FF, + CyanA700 = 0xFF00B8D4, + // Teal Teal50 = 0xFFE0F2F1, Teal100 = 0xFFB2DFDB, @@ -138,6 +178,11 @@ namespace Avalonia.Controls Teal800 = 0xFF00695C, Teal900 = 0xFF004D40, + TealA100 = 0xFFA7FFEB, + TealA200 = 0xFF64FFDA, + TealA400 = 0xFF1DE9B6, + TealA700 = 0xFF00BFA5, + // Green Green50 = 0xFFE8F5E9, Green100 = 0xFFC8E6C9, @@ -150,6 +195,11 @@ namespace Avalonia.Controls Green800 = 0xFF2E7D32, Green900 = 0xFF1B5E20, + GreenA100 = 0xFFB9F6CA, + GreenA200 = 0xFF69F0AE, + GreenA400 = 0xFF00E676, + GreenA700 = 0xFF00C853, + // Light Green LightGreen50 = 0xFFF1F8E9, LightGreen100 = 0xFFDCEDC8, @@ -162,6 +212,11 @@ namespace Avalonia.Controls LightGreen800 = 0xFF558B2F, LightGreen900 = 0xFF33691E, + LightGreenA100 = 0xFFCCFF90, + LightGreenA200 = 0xFFB2FF59, + LightGreenA400 = 0xFF76FF03, + LightGreenA700 = 0xFF64DD17, + // Lime Lime50 = 0xFFF9FBE7, Lime100 = 0xFFF0F4C3, @@ -174,6 +229,11 @@ namespace Avalonia.Controls Lime800 = 0xFF9E9D24, Lime900 = 0xFF827717, + LimeA100 = 0xFFF4FF81, + LimeA200 = 0xFFEEFF41, + LimeA400 = 0xFFC6FF00, + LimeA700 = 0xFFAEEA00, + // Yellow Yellow50 = 0xFFFFFDE7, Yellow100 = 0xFFFFF9C4, @@ -186,6 +246,11 @@ namespace Avalonia.Controls Yellow800 = 0xFFF9A825, Yellow900 = 0xFFF57F17, + YellowA100 = 0xFFFFFF8D, + YellowA200 = 0xFFFFFF00, + YellowA400 = 0xFFFFEA00, + YellowA700 = 0xFFFFD600, + // Amber Amber50 = 0xFFFFF8E1, Amber100 = 0xFFFFECB3, @@ -198,6 +263,11 @@ namespace Avalonia.Controls Amber800 = 0xFFFF8F00, Amber900 = 0xFFFF6F00, + AmberA100 = 0xFFFFE57F, + AmberA200 = 0xFFFFD740, + AmberA400 = 0xFFFFC400, + AmberA700 = 0xFFFFAB00, + // Orange Orange50 = 0xFFFFF3E0, Orange100 = 0xFFFFE0B2, @@ -210,6 +280,11 @@ namespace Avalonia.Controls Orange800 = 0xFFEF6C00, Orange900 = 0xFFE65100, + OrangeA100 = 0xFFFFD180, + OrangeA200 = 0xFFFFAB40, + OrangeA400 = 0xFFFF9100, + OrangeA700 = 0xFFFF6D00, + // Deep Orange DeepOrange50 = 0xFFFBE9E7, DeepOrange100 = 0xFFFFCCBC, @@ -222,6 +297,11 @@ namespace Avalonia.Controls DeepOrange800 = 0xFFD84315, DeepOrange900 = 0xFFBF360C, + DeepOrangeA100 = 0xFFFF9E80, + DeepOrangeA200 = 0xFFFF6E40, + DeepOrangeA400 = 0xFFFF3D00, + DeepOrangeA700 = 0xFFDD2C00, + // Brown Brown50 = 0xFFEFEBE9, Brown100 = 0xFFD7CCC8, @@ -257,6 +337,9 @@ namespace Avalonia.Controls BlueGray700 = 0xFF455A64, BlueGray800 = 0xFF37474F, BlueGray900 = 0xFF263238, + + Black = 0xFF000000, + White = 0xFFFFFFFF, } // See: https://material.io/design/color/the-color-system.html#tools-for-picking-colors diff --git a/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs index e92ad02c7a..ce843952e7 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs @@ -23,5 +23,11 @@ namespace Avalonia.LinuxFramebuffer /// Default: R0 G0 B0 A0 /// public Color InitialBufferSwappingColor { get; set; } = new Color(0, 0, 0, 0); + + /// + /// specific the video mode with which the DrmOutput should be created, if it is not found it will fallback to the preferred mode. + /// If NULL preferred mode will be used. + /// + public PixelSize? VideoMode { get; set; } } } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Pointer.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Pointer.cs new file mode 100644 index 0000000000..ef039a38bc --- /dev/null +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Pointer.cs @@ -0,0 +1,110 @@ +using System; +using Avalonia.Input; +using Avalonia.Input.Raw; +using Avalonia.Logging; +using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; + +namespace Avalonia.LinuxFramebuffer.Input.LibInput; + +public partial class LibInputBackend +{ + private MouseDevice _mouse = new MouseDevice(); + private Point _mousePosition; + private const string Pointer = LibInput + "/" + nameof(Pointer); + + private void HandlePointer(IntPtr ev, LibInputEventType type) + { + var modifiers = RawInputModifiers.None; //TODO: support input modifiers + var pev = libinput_event_get_pointer_event(ev); + var info = _screen.ScaledSize; + var ts = libinput_event_pointer_get_time_usec(pev) / 1000; + switch (type) + { + case LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + _mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width), + libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height)); + ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition, + modifiers)); + break; + case LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON: + { + var button = (EvKey)libinput_event_pointer_get_button(pev); + var buttonState = libinput_event_pointer_get_button_state(pev); + + RawPointerEventArgs evnt = button switch + { + EvKey.BTN_LEFT when buttonState == 1 + => new(_mouse, ts, _inputRoot, RawPointerEventType.LeftButtonDown, _mousePosition, modifiers), + EvKey.BTN_LEFT when buttonState == 0 + => new(_mouse, ts, _inputRoot, RawPointerEventType.LeftButtonUp, _mousePosition, modifiers), + EvKey.BTN_RIGHT when buttonState == 1 + => new(_mouse, ts, _inputRoot, RawPointerEventType.RightButtonUp, _mousePosition, modifiers), + EvKey.BTN_RIGHT when buttonState == 2 + => new(_mouse, ts, _inputRoot, RawPointerEventType.RightButtonDown, _mousePosition, modifiers), + EvKey.BTN_MIDDLE when buttonState == 1 + => new(_mouse, ts, _inputRoot, RawPointerEventType.MiddleButtonDown, _mousePosition, modifiers), + EvKey.BTN_MIDDLE when buttonState == 2 + => new(_mouse, ts, _inputRoot, RawPointerEventType.MiddleButtonUp, _mousePosition, modifiers), + _ => default, + }; + if (evnt is not null) + { + ScheduleInput(evnt); + } + else + { + Logger.TryGet(LogEventLevel.Warning, Pointer) + ?.Log(this, $"The button {button} is not associated"); + } + } + break; + // Backward compatibility with low-res wheel + case LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS: + { + var sourceAxis = libinput_event_pointer_get_axis_source(pev); + switch (sourceAxis) + { + case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: + { + var value = libinput_event_pointer_get_axis_value_discrete(pev, + LibInputPointerAxis.LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + ScheduleInput(new RawMouseWheelEventArgs(_mouse + , ts + , _inputRoot + , _mousePosition + , new Vector(0, -value) + , modifiers)); + } + break; + case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_FINGER: + case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: + case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: + default: + Logger.TryGet(LogEventLevel.Debug, Pointer) + ?.Log(this, $"The pointer axis {sourceAxis} is not managed."); + break; + } + } + break; + // Hi-Res wheel + case LibInputEventType.LIBINPUT_EVENT_POINTER_SCROLL_WHEEL: + { + var value = new Vector(0, + -libinput_event_pointer_get_scroll_value_v120(pev, + LibInputPointerAxis.LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) / 120); + ScheduleInput(new RawMouseWheelEventArgs(_mouse + , ts + , _inputRoot + , _mousePosition + , value + , modifiers)); + } + break; + default: + Logger.TryGet(LogEventLevel.Warning, Pointer) + ?.Log(this, $"The pointer event {type} is not mapped."); + break; + } + + } +} diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 702ae3f8e5..77e8202fac 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -4,18 +4,16 @@ using System.IO; using System.Threading; using Avalonia.Input; using Avalonia.Input.Raw; -using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; +using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; namespace Avalonia.LinuxFramebuffer.Input.LibInput { - public class LibInputBackend : IInputBackend + public partial class LibInputBackend : IInputBackend { private IScreenInfoProvider _screen; private IInputRoot _inputRoot; private readonly Queue _inputThreadActions = new Queue(); private TouchDevice _touch = new TouchDevice(); - private MouseDevice _mouse = new MouseDevice(); - private Point _mousePosition; - + private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput); private readonly RawEventGroupingThreadingHelper _inputQueue; private Action _onInput; private Dictionary _pointers = new Dictionary(); @@ -24,13 +22,13 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput { var ctx = libinput_path_create_context(); _inputQueue = new(e => _onInput?.Invoke(e)); - new Thread(()=>InputThread(ctx)).Start(); + new Thread(() => InputThread(ctx)).Start(); } private unsafe void InputThread(IntPtr ctx) { var fd = libinput_get_fd(ctx); - + var timeval = stackalloc IntPtr[2]; @@ -38,12 +36,11 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput libinput_path_add_device(ctx, f); while (true) { - IntPtr ev; libinput_dispatch(ctx); while ((ev = libinput_get_event(ctx)) != IntPtr.Zero) { - + var type = libinput_event_get_type(ev); if (type >= LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN && type <= LibInputEventType.LIBINPUT_EVENT_TOUCH_CANCEL) @@ -52,12 +49,12 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput if (type >= LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION && type <= LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS) HandlePointer(ev, type); - + libinput_event_destroy(ev); libinput_dispatch(ctx); } - pollfd pfd = new pollfd {fd = fd, events = 1}; + pollfd pfd = new pollfd { fd = fd, events = 1 }; NativeUnsafeMethods.poll(&pfd, new IntPtr(1), 10); } } @@ -67,7 +64,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput private void HandleTouch(IntPtr ev, LibInputEventType type) { var tev = libinput_event_get_touch_event(ev); - if(tev == IntPtr.Zero) + if (tev == IntPtr.Zero) return; if (type < LibInputEventType.LIBINPUT_EVENT_TOUCH_FRAME) { @@ -102,44 +99,6 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput } } - private void HandlePointer(IntPtr ev, LibInputEventType type) - { - //TODO: support input modifiers - var pev = libinput_event_get_pointer_event(ev); - var info = _screen.ScaledSize; - var ts = libinput_event_pointer_get_time_usec(pev) / 1000; - if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE) - { - _mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width), - libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height)); - ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition, - RawInputModifiers.None)); - } - else if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON) - { - var button = (EvKey)libinput_event_pointer_get_button(pev); - var buttonState = libinput_event_pointer_get_button_state(pev); - - - var evnt = button == EvKey.BTN_LEFT ? - (buttonState == 1 ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp) : - button == EvKey.BTN_MIDDLE ? - (buttonState == 1 ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp) : - button == EvKey.BTN_RIGHT ? - (buttonState == 1 ? - RawPointerEventType.RightButtonDown : - RawPointerEventType.RightButtonUp) : - (RawPointerEventType)(-1); - if (evnt == (RawPointerEventType)(-1)) - return; - - - ScheduleInput( - new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, RawInputModifiers.None)); - } - - } - public void Initialize(IScreenInfoProvider screen, Action onInput) { _screen = screen; diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs index 0492090461..df6defb653 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs @@ -77,6 +77,9 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, LIBINPUT_EVENT_POINTER_BUTTON, LIBINPUT_EVENT_POINTER_AXIS, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, LIBINPUT_EVENT_TOUCH_DOWN = 500, LIBINPUT_EVENT_TOUCH_UP, LIBINPUT_EVENT_TOUCH_MOTION, @@ -97,8 +100,38 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput LIBINPUT_EVENT_GESTURE_PINCH_END, LIBINPUT_EVENT_SWITCH_TOGGLE = 900, } - - + + public enum LibInputPointerAxisSource + { + /** + * The event is caused by the rotation of a wheel. + **/ + LIBINPUT_POINTER_AXIS_SOURCE_WHEEL = 1, + /** + * The event is caused by the movement of one or more fingers on a device. + **/ + LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + /** + * The event is caused by the motion of some device. + **/ + LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, + /** + * The event is caused by the tilting of a mouse wheel rather than + * its rotation. This method is commonly used on mice without + * separate horizontal scroll wheels. + * @deprecated This axis source is deprecated as of libinput 1.16. + * It was never used by any device before libinput 1.16. All wheel + * tilt devices use @ref LIBINPUT_POINTER_AXIS_SOURCE_WHEEL instead. + **/ + LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT, + }; + + public enum LibInputPointerAxis + { + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL = 0, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL = 1, + }; + [DllImport(LibInput)] public extern static void libinput_event_destroy(IntPtr ev); @@ -119,21 +152,29 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput [DllImport(LibInput)] public extern static IntPtr libinput_event_get_pointer_event(IntPtr ev); - - + [DllImport(LibInput)] public extern static ulong libinput_event_pointer_get_time_usec(IntPtr ev); [DllImport(LibInput)] public extern static double libinput_event_pointer_get_absolute_x_transformed(IntPtr ev, int width); - + [DllImport(LibInput)] public extern static double libinput_event_pointer_get_absolute_y_transformed(IntPtr ev, int height); - + [DllImport(LibInput)] public extern static int libinput_event_pointer_get_button(IntPtr ev); [DllImport(LibInput)] public extern static int libinput_event_pointer_get_button_state(IntPtr ev); + + [DllImport(LibInput)] + public extern static LibInputPointerAxisSource libinput_event_pointer_get_axis_source(IntPtr ev); + + [DllImport((LibInput))] + public extern static double libinput_event_pointer_get_axis_value_discrete(IntPtr ev, LibInputPointerAxis axis); + + [DllImport(LibInput)] + public extern static double libinput_event_pointer_get_scroll_value_v120(IntPtr ev, LibInputPointerAxis axis); } } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs index 5c7ec2bbd2..a4d7d8b1eb 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs @@ -51,7 +51,16 @@ namespace Avalonia.LinuxFramebuffer.Output if(connector == null) throw new InvalidOperationException("Unable to find connected DRM connector"); - var mode = connector.Modes.OrderByDescending(x => x.IsPreferred) + DrmModeInfo? mode = null; + + if (options?.VideoMode != null) + { + mode = connector.Modes + .FirstOrDefault(x => x.Resolution.Width == options.VideoMode.Value.Width && + x.Resolution.Height == options.VideoMode.Value.Height); + } + + mode ??= connector.Modes.OrderByDescending(x => x.IsPreferred) .ThenByDescending(x => x.Resolution.Width * x.Resolution.Height) //.OrderByDescending(x => x.Resolution.Width * x.Resolution.Height) .FirstOrDefault(); diff --git a/src/Web/Avalonia.Web/Avalonia.Web.targets b/src/Web/Avalonia.Web/Avalonia.Web.targets index b6a09b33ef..22363b33d8 100644 --- a/src/Web/Avalonia.Web/Avalonia.Web.targets +++ b/src/Web/Avalonia.Web/Avalonia.Web.targets @@ -12,7 +12,7 @@ true - + true full true