Browse Source

Merge branch 'master' into fixes/tapped-gestures

pull/9360/head
Steven Kirk 4 years ago
parent
commit
86cd89cc26
  1. 12
      azure-pipelines.yml
  2. 2
      global.json
  3. 5
      native/Avalonia.Native/src/OSX/rendertarget.mm
  4. 19
      nukebuild/Build.cs
  5. 4
      nukebuild/_build.csproj
  6. 22
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  7. 6
      src/Avalonia.Base/Layout/UniformGridLayoutState.cs
  8. 83
      src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs
  9. 6
      src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs
  10. 110
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Pointer.cs
  11. 59
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs
  12. 53
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs
  13. 11
      src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs
  14. 2
      src/Web/Avalonia.Web/Avalonia.Web.targets

12
azure-pipelines.yml

@ -35,9 +35,9 @@ jobs:
version: 6.0.401 version: 6.0.401
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23' displayName: 'Use .NET Core SDK 7.0'
inputs: inputs:
version: 7.0.100-rc.2.22477.23 version: 7.0.100
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'
@ -72,9 +72,9 @@ jobs:
version: 6.0.401 version: 6.0.401
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23' displayName: 'Use .NET Core SDK 7.0.100'
inputs: inputs:
version: 7.0.100-rc.2.22477.23 version: 7.0.100
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'
@ -143,9 +143,9 @@ jobs:
version: 6.0.401 version: 6.0.401
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 7.0.100-rc.2.22477.23' displayName: 'Use .NET Core SDK 7.0.100'
inputs: inputs:
version: 7.0.100-rc.2.22477.23 version: 7.0.100
- task: CmdLine@2 - task: CmdLine@2
displayName: 'Install Workloads' displayName: 'Install Workloads'

2
global.json

@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "7.0.100-rc.2.22477.23", "version": "7.0.100",
"rollForward": "latestFeature" "rollForward": "latestFeature"
}, },
"msbuild-sdks": { "msbuild-sdks": {

5
native/Avalonia.Native/src/OSX/rendertarget.mm

@ -183,8 +183,11 @@ static IAvnGlSurfaceRenderTarget* CreateGlRenderTarget(IOSurfaceRenderTarget* ta
[_layer setContents: (__bridge IOSurface*) surface->surface]; [_layer setContents: (__bridge IOSurface*) surface->surface];
} }
[CATransaction commit]; [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 else
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{

19
nukebuild/Build.cs

@ -145,8 +145,25 @@ partial class Build : NukeBuild
{ {
Information($"Running tests from {projectName}"); Information($"Running tests from {projectName}");
var project = Solution.GetProject(projectName).NotNull("project != null"); 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") if (fw.StartsWith("net4")
&& RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.IsOSPlatform(OSPlatform.Linux)

4
nukebuild/_build.csproj

@ -16,8 +16,8 @@
<PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" /> <PackageReference Include="MicroCom.CodeGenerator" Version="0.11.0" />
<!-- Keep in sync with Avalonia.Build.Tasks --> <!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Mono.Cecil" Version="0.11.4" /> <PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" /> <PackageReference Include="SourceLink" Version="1.1.0" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.3.1" PrivateAssets="All" /> <PackageReference Include="Microsoft.Build.Framework" Version="17.3.2" PrivateAssets="All" />
<PackageReference Include="xunit.runner.console" Version="2.4.2"> <PackageReference Include="xunit.runner.console" Version="2.4.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

22
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -165,6 +165,28 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_tl.Draw(); _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) protected override bool DispatchGenericPointerEvent(MotionEvent e)
{ {
bool callBase; bool callBase;

6
src/Avalonia.Base/Layout/UniformGridLayoutState.cs

@ -117,12 +117,12 @@ namespace Avalonia.Layout
double extraMinorPixelsForEachItem = 0.0; double extraMinorPixelsForEachItem = 0.0;
if (!double.IsInfinity(availableSizeMinor)) if (!double.IsInfinity(availableSizeMinor))
{ {
var numItemsPerColumn = Math.Min( var numItemsPerColumn = (int)Math.Min(
maxItemsPerLine, maxItemsPerLine,
Math.Max(1.0, availableSizeMinor / (itemSizeMinor + minorItemSpacing))); Math.Max(1.0, availableSizeMinor / (itemSizeMinor + minorItemSpacing)));
var usedSpace = (numItemsPerColumn * (itemSizeMinor + minorItemSpacing)) - minorItemSpacing; var usedSpace = (numItemsPerColumn * (itemSizeMinor + minorItemSpacing)) - minorItemSpacing;
var remainingSpace = ((int)(availableSizeMinor - usedSpace)); var remainingSpace = availableSizeMinor - usedSpace;
extraMinorPixelsForEachItem = remainingSpace / ((int)numItemsPerColumn); extraMinorPixelsForEachItem = (int)(remainingSpace / numItemsPerColumn);
} }
if (stretch == UniformGridLayoutItemsStretch.Fill) if (stretch == UniformGridLayoutItemsStretch.Fill)

83
src/Avalonia.Controls.ColorPicker/ColorPalettes/MaterialColorPalette.cs

@ -42,6 +42,11 @@ namespace Avalonia.Controls
Red800 = 0xFFC62828, Red800 = 0xFFC62828,
Red900 = 0xFFB71C1C, Red900 = 0xFFB71C1C,
RedA100 = 0xFFFF8A80,
RedA200 = 0xFFFF5252,
RedA400 = 0xFFFF1744,
RedA700 = 0xFFD50000,
// Pink // Pink
Pink50 = 0xFFFCE4EC, Pink50 = 0xFFFCE4EC,
Pink100 = 0xFFF8BBD0, Pink100 = 0xFFF8BBD0,
@ -54,6 +59,11 @@ namespace Avalonia.Controls
Pink800 = 0xFFAD1457, Pink800 = 0xFFAD1457,
Pink900 = 0xFF880E4F, Pink900 = 0xFF880E4F,
PinkA100 = 0xFFFF80AB,
PinkA200 = 0xFFFF4081,
PinkA400 = 0xFFF50057,
PinkA700 = 0xFFC51162,
// Purple // Purple
Purple50 = 0xFFF3E5F5, Purple50 = 0xFFF3E5F5,
Purple100 = 0xFFE1BEE7, Purple100 = 0xFFE1BEE7,
@ -66,6 +76,11 @@ namespace Avalonia.Controls
Purple800 = 0xFF6A1B9A, Purple800 = 0xFF6A1B9A,
Purple900 = 0xFF4A148C, Purple900 = 0xFF4A148C,
PurpleA100 = 0xFFEA80FC,
PurpleA200 = 0xFFE040FB,
PurpleA400 = 0xFFD500F9,
PurpleA700 = 0xFFAA00FF,
// Deep Purple // Deep Purple
DeepPurple50 = 0xFFEDE7F6, DeepPurple50 = 0xFFEDE7F6,
DeepPurple100 = 0xFFD1C4E9, DeepPurple100 = 0xFFD1C4E9,
@ -78,6 +93,11 @@ namespace Avalonia.Controls
DeepPurple800 = 0xFF4527A0, DeepPurple800 = 0xFF4527A0,
DeepPurple900 = 0xFF311B92, DeepPurple900 = 0xFF311B92,
DeepPurpleA100 = 0xFFB388FF,
DeepPurpleA200 = 0xFF7C4DFF,
DeepPurpleA400 = 0xFF651FFF,
DeepPurpleA700 = 0xFF6200EA,
// Indigo // Indigo
Indigo50 = 0xFFE8EAF6, Indigo50 = 0xFFE8EAF6,
Indigo100 = 0xFFC5CAE9, Indigo100 = 0xFFC5CAE9,
@ -90,6 +110,11 @@ namespace Avalonia.Controls
Indigo800 = 0xFF283593, Indigo800 = 0xFF283593,
Indigo900 = 0xFF1A237E, Indigo900 = 0xFF1A237E,
IndigoA100 = 0xFF8C9EFF,
IndigoA200 = 0xFF536DFE,
IndigoA400 = 0xFF3D5AFE,
IndigoA700 = 0xFF304FFE,
// Blue // Blue
Blue50 = 0xFFE3F2FD, Blue50 = 0xFFE3F2FD,
Blue100 = 0xFFBBDEFB, Blue100 = 0xFFBBDEFB,
@ -102,6 +127,11 @@ namespace Avalonia.Controls
Blue800 = 0xFF1565C0, Blue800 = 0xFF1565C0,
Blue900 = 0xFF0D47A1, Blue900 = 0xFF0D47A1,
BlueA100 = 0xFF82B1FF,
BlueA200 = 0xFF448AFF,
BlueA400 = 0xFF2979FF,
BlueA700 = 0xFF2962FF,
// Light Blue // Light Blue
LightBlue50 = 0xFFE1F5FE, LightBlue50 = 0xFFE1F5FE,
LightBlue100 = 0xFFB3E5FC, LightBlue100 = 0xFFB3E5FC,
@ -114,6 +144,11 @@ namespace Avalonia.Controls
LightBlue800 = 0xFF0277BD, LightBlue800 = 0xFF0277BD,
LightBlue900 = 0xFF01579B, LightBlue900 = 0xFF01579B,
LightBlueA100 = 0xFF80D8FF,
LightBlueA200 = 0xFF40C4FF,
LightBlueA400 = 0xFF00B0FF,
LightBlueA700 = 0xFF0091EA,
// Cyan // Cyan
Cyan50 = 0xFFE0F7FA, Cyan50 = 0xFFE0F7FA,
Cyan100 = 0xFFB2EBF2, Cyan100 = 0xFFB2EBF2,
@ -126,6 +161,11 @@ namespace Avalonia.Controls
Cyan800 = 0xFF00838F, Cyan800 = 0xFF00838F,
Cyan900 = 0xFF006064, Cyan900 = 0xFF006064,
CyanA100 = 0xFF84FFFF,
CyanA200 = 0xFF18FFFF,
CyanA400 = 0xFF00E5FF,
CyanA700 = 0xFF00B8D4,
// Teal // Teal
Teal50 = 0xFFE0F2F1, Teal50 = 0xFFE0F2F1,
Teal100 = 0xFFB2DFDB, Teal100 = 0xFFB2DFDB,
@ -138,6 +178,11 @@ namespace Avalonia.Controls
Teal800 = 0xFF00695C, Teal800 = 0xFF00695C,
Teal900 = 0xFF004D40, Teal900 = 0xFF004D40,
TealA100 = 0xFFA7FFEB,
TealA200 = 0xFF64FFDA,
TealA400 = 0xFF1DE9B6,
TealA700 = 0xFF00BFA5,
// Green // Green
Green50 = 0xFFE8F5E9, Green50 = 0xFFE8F5E9,
Green100 = 0xFFC8E6C9, Green100 = 0xFFC8E6C9,
@ -150,6 +195,11 @@ namespace Avalonia.Controls
Green800 = 0xFF2E7D32, Green800 = 0xFF2E7D32,
Green900 = 0xFF1B5E20, Green900 = 0xFF1B5E20,
GreenA100 = 0xFFB9F6CA,
GreenA200 = 0xFF69F0AE,
GreenA400 = 0xFF00E676,
GreenA700 = 0xFF00C853,
// Light Green // Light Green
LightGreen50 = 0xFFF1F8E9, LightGreen50 = 0xFFF1F8E9,
LightGreen100 = 0xFFDCEDC8, LightGreen100 = 0xFFDCEDC8,
@ -162,6 +212,11 @@ namespace Avalonia.Controls
LightGreen800 = 0xFF558B2F, LightGreen800 = 0xFF558B2F,
LightGreen900 = 0xFF33691E, LightGreen900 = 0xFF33691E,
LightGreenA100 = 0xFFCCFF90,
LightGreenA200 = 0xFFB2FF59,
LightGreenA400 = 0xFF76FF03,
LightGreenA700 = 0xFF64DD17,
// Lime // Lime
Lime50 = 0xFFF9FBE7, Lime50 = 0xFFF9FBE7,
Lime100 = 0xFFF0F4C3, Lime100 = 0xFFF0F4C3,
@ -174,6 +229,11 @@ namespace Avalonia.Controls
Lime800 = 0xFF9E9D24, Lime800 = 0xFF9E9D24,
Lime900 = 0xFF827717, Lime900 = 0xFF827717,
LimeA100 = 0xFFF4FF81,
LimeA200 = 0xFFEEFF41,
LimeA400 = 0xFFC6FF00,
LimeA700 = 0xFFAEEA00,
// Yellow // Yellow
Yellow50 = 0xFFFFFDE7, Yellow50 = 0xFFFFFDE7,
Yellow100 = 0xFFFFF9C4, Yellow100 = 0xFFFFF9C4,
@ -186,6 +246,11 @@ namespace Avalonia.Controls
Yellow800 = 0xFFF9A825, Yellow800 = 0xFFF9A825,
Yellow900 = 0xFFF57F17, Yellow900 = 0xFFF57F17,
YellowA100 = 0xFFFFFF8D,
YellowA200 = 0xFFFFFF00,
YellowA400 = 0xFFFFEA00,
YellowA700 = 0xFFFFD600,
// Amber // Amber
Amber50 = 0xFFFFF8E1, Amber50 = 0xFFFFF8E1,
Amber100 = 0xFFFFECB3, Amber100 = 0xFFFFECB3,
@ -198,6 +263,11 @@ namespace Avalonia.Controls
Amber800 = 0xFFFF8F00, Amber800 = 0xFFFF8F00,
Amber900 = 0xFFFF6F00, Amber900 = 0xFFFF6F00,
AmberA100 = 0xFFFFE57F,
AmberA200 = 0xFFFFD740,
AmberA400 = 0xFFFFC400,
AmberA700 = 0xFFFFAB00,
// Orange // Orange
Orange50 = 0xFFFFF3E0, Orange50 = 0xFFFFF3E0,
Orange100 = 0xFFFFE0B2, Orange100 = 0xFFFFE0B2,
@ -210,6 +280,11 @@ namespace Avalonia.Controls
Orange800 = 0xFFEF6C00, Orange800 = 0xFFEF6C00,
Orange900 = 0xFFE65100, Orange900 = 0xFFE65100,
OrangeA100 = 0xFFFFD180,
OrangeA200 = 0xFFFFAB40,
OrangeA400 = 0xFFFF9100,
OrangeA700 = 0xFFFF6D00,
// Deep Orange // Deep Orange
DeepOrange50 = 0xFFFBE9E7, DeepOrange50 = 0xFFFBE9E7,
DeepOrange100 = 0xFFFFCCBC, DeepOrange100 = 0xFFFFCCBC,
@ -222,6 +297,11 @@ namespace Avalonia.Controls
DeepOrange800 = 0xFFD84315, DeepOrange800 = 0xFFD84315,
DeepOrange900 = 0xFFBF360C, DeepOrange900 = 0xFFBF360C,
DeepOrangeA100 = 0xFFFF9E80,
DeepOrangeA200 = 0xFFFF6E40,
DeepOrangeA400 = 0xFFFF3D00,
DeepOrangeA700 = 0xFFDD2C00,
// Brown // Brown
Brown50 = 0xFFEFEBE9, Brown50 = 0xFFEFEBE9,
Brown100 = 0xFFD7CCC8, Brown100 = 0xFFD7CCC8,
@ -257,6 +337,9 @@ namespace Avalonia.Controls
BlueGray700 = 0xFF455A64, BlueGray700 = 0xFF455A64,
BlueGray800 = 0xFF37474F, BlueGray800 = 0xFF37474F,
BlueGray900 = 0xFF263238, BlueGray900 = 0xFF263238,
Black = 0xFF000000,
White = 0xFFFFFFFF,
} }
// See: https://material.io/design/color/the-color-system.html#tools-for-picking-colors // See: https://material.io/design/color/the-color-system.html#tools-for-picking-colors

6
src/Linux/Avalonia.LinuxFramebuffer/DrmOutputOptions.cs

@ -23,5 +23,11 @@ namespace Avalonia.LinuxFramebuffer
/// Default: R0 G0 B0 A0 /// Default: R0 G0 B0 A0
/// </summary> /// </summary>
public Color InitialBufferSwappingColor { get; set; } = new Color(0, 0, 0, 0); public Color InitialBufferSwappingColor { get; set; } = new Color(0, 0, 0, 0);
/// <summary>
/// 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.
/// </summary>
public PixelSize? VideoMode { get; set; }
} }
} }

110
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;
}
}
}

59
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs

@ -4,18 +4,16 @@ using System.IO;
using System.Threading; using System.Threading;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods; using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
namespace Avalonia.LinuxFramebuffer.Input.LibInput namespace Avalonia.LinuxFramebuffer.Input.LibInput
{ {
public class LibInputBackend : IInputBackend public partial class LibInputBackend : IInputBackend
{ {
private IScreenInfoProvider _screen; private IScreenInfoProvider _screen;
private IInputRoot _inputRoot; private IInputRoot _inputRoot;
private readonly Queue<Action> _inputThreadActions = new Queue<Action>(); private readonly Queue<Action> _inputThreadActions = new Queue<Action>();
private TouchDevice _touch = new TouchDevice(); private TouchDevice _touch = new TouchDevice();
private MouseDevice _mouse = new MouseDevice(); private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput);
private Point _mousePosition;
private readonly RawEventGroupingThreadingHelper _inputQueue; private readonly RawEventGroupingThreadingHelper _inputQueue;
private Action<RawInputEventArgs> _onInput; private Action<RawInputEventArgs> _onInput;
private Dictionary<int, Point> _pointers = new Dictionary<int, Point>(); private Dictionary<int, Point> _pointers = new Dictionary<int, Point>();
@ -24,13 +22,13 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
{ {
var ctx = libinput_path_create_context(); var ctx = libinput_path_create_context();
_inputQueue = new(e => _onInput?.Invoke(e)); _inputQueue = new(e => _onInput?.Invoke(e));
new Thread(()=>InputThread(ctx)).Start(); new Thread(() => InputThread(ctx)).Start();
} }
private unsafe void InputThread(IntPtr ctx) private unsafe void InputThread(IntPtr ctx)
{ {
var fd = libinput_get_fd(ctx); var fd = libinput_get_fd(ctx);
var timeval = stackalloc IntPtr[2]; var timeval = stackalloc IntPtr[2];
@ -38,12 +36,11 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
libinput_path_add_device(ctx, f); libinput_path_add_device(ctx, f);
while (true) while (true)
{ {
IntPtr ev; IntPtr ev;
libinput_dispatch(ctx); libinput_dispatch(ctx);
while ((ev = libinput_get_event(ctx)) != IntPtr.Zero) while ((ev = libinput_get_event(ctx)) != IntPtr.Zero)
{ {
var type = libinput_event_get_type(ev); var type = libinput_event_get_type(ev);
if (type >= LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN && if (type >= LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN &&
type <= LibInputEventType.LIBINPUT_EVENT_TOUCH_CANCEL) type <= LibInputEventType.LIBINPUT_EVENT_TOUCH_CANCEL)
@ -52,12 +49,12 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
if (type >= LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION if (type >= LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION
&& type <= LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS) && type <= LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS)
HandlePointer(ev, type); HandlePointer(ev, type);
libinput_event_destroy(ev); libinput_event_destroy(ev);
libinput_dispatch(ctx); 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); NativeUnsafeMethods.poll(&pfd, new IntPtr(1), 10);
} }
} }
@ -67,7 +64,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
private void HandleTouch(IntPtr ev, LibInputEventType type) private void HandleTouch(IntPtr ev, LibInputEventType type)
{ {
var tev = libinput_event_get_touch_event(ev); var tev = libinput_event_get_touch_event(ev);
if(tev == IntPtr.Zero) if (tev == IntPtr.Zero)
return; return;
if (type < LibInputEventType.LIBINPUT_EVENT_TOUCH_FRAME) 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<RawInputEventArgs> onInput) public void Initialize(IScreenInfoProvider screen, Action<RawInputEventArgs> onInput)
{ {
_screen = screen; _screen = screen;

53
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_MOTION_ABSOLUTE,
LIBINPUT_EVENT_POINTER_BUTTON, LIBINPUT_EVENT_POINTER_BUTTON,
LIBINPUT_EVENT_POINTER_AXIS, 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_DOWN = 500,
LIBINPUT_EVENT_TOUCH_UP, LIBINPUT_EVENT_TOUCH_UP,
LIBINPUT_EVENT_TOUCH_MOTION, LIBINPUT_EVENT_TOUCH_MOTION,
@ -97,8 +100,38 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
LIBINPUT_EVENT_GESTURE_PINCH_END, LIBINPUT_EVENT_GESTURE_PINCH_END,
LIBINPUT_EVENT_SWITCH_TOGGLE = 900, 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)] [DllImport(LibInput)]
public extern static void libinput_event_destroy(IntPtr ev); public extern static void libinput_event_destroy(IntPtr ev);
@ -119,21 +152,29 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
[DllImport(LibInput)] [DllImport(LibInput)]
public extern static IntPtr libinput_event_get_pointer_event(IntPtr ev); public extern static IntPtr libinput_event_get_pointer_event(IntPtr ev);
[DllImport(LibInput)] [DllImport(LibInput)]
public extern static ulong libinput_event_pointer_get_time_usec(IntPtr ev); public extern static ulong libinput_event_pointer_get_time_usec(IntPtr ev);
[DllImport(LibInput)] [DllImport(LibInput)]
public extern static double libinput_event_pointer_get_absolute_x_transformed(IntPtr ev, int width); public extern static double libinput_event_pointer_get_absolute_x_transformed(IntPtr ev, int width);
[DllImport(LibInput)] [DllImport(LibInput)]
public extern static double libinput_event_pointer_get_absolute_y_transformed(IntPtr ev, int height); public extern static double libinput_event_pointer_get_absolute_y_transformed(IntPtr ev, int height);
[DllImport(LibInput)] [DllImport(LibInput)]
public extern static int libinput_event_pointer_get_button(IntPtr ev); public extern static int libinput_event_pointer_get_button(IntPtr ev);
[DllImport(LibInput)] [DllImport(LibInput)]
public extern static int libinput_event_pointer_get_button_state(IntPtr ev); 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);
} }
} }

11
src/Linux/Avalonia.LinuxFramebuffer/Output/DrmOutput.cs

@ -51,7 +51,16 @@ namespace Avalonia.LinuxFramebuffer.Output
if(connector == null) if(connector == null)
throw new InvalidOperationException("Unable to find connected DRM connector"); 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) .ThenByDescending(x => x.Resolution.Width * x.Resolution.Height)
//.OrderByDescending(x => x.Resolution.Width * x.Resolution.Height) //.OrderByDescending(x => x.Resolution.Width * x.Resolution.Height)
.FirstOrDefault(); .FirstOrDefault();

2
src/Web/Avalonia.Web/Avalonia.Web.targets

@ -12,7 +12,7 @@
<WasmBuildNative>true</WasmBuildNative> <WasmBuildNative>true</WasmBuildNative>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(UseAvaloniaWasmDefaultOptimizations)'=='True'"> <PropertyGroup Condition="'$(UseAvaloniaWasmDefaultOptimizations)'=='True' And '$(Configuration)' == 'Release'">
<PublishTrimmed>true</PublishTrimmed> <PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode> <TrimMode>full</TrimMode>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>

Loading…
Cancel
Save