Browse Source

Merge branch 'add-xmlnsprefix' of https://github.com/bmello4688/Avalonia into add-xmlnsprefix

pull/4891/head
bmello4688 6 years ago
parent
commit
eccfd4021c
  1. 2
      samples/BindingDemo/App.xaml.cs
  2. 2
      samples/ControlCatalog.Desktop/Program.cs
  3. 2
      samples/ControlCatalog.NetCore/Program.cs
  4. 2
      samples/RenderDemo/App.xaml.cs
  5. 2
      samples/Sandbox/Program.cs
  6. 2
      samples/VirtualizationDemo/Program.cs
  7. 3
      src/Avalonia.Base/ApiCompatBaseline.txt
  8. 14
      src/Avalonia.Base/Logging/TraceLogSink.cs
  9. 13
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  10. 13
      src/Avalonia.Controls/ContextMenu.cs
  11. 2
      src/Avalonia.Controls/ItemsControl.cs
  12. 19
      src/Avalonia.Controls/LoggingExtensions.cs
  13. 7
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  14. 2
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  15. 20
      src/Avalonia.Input/MouseDevice.cs
  16. 1
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  17. 4
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  18. 14
      src/Avalonia.Visuals/Media/Drawing.cs
  19. 4
      src/Avalonia.Visuals/Media/Geometry.cs
  20. 44
      src/Avalonia.Visuals/Media/GeometryDrawing.cs
  21. 84
      src/Avalonia.X11/XI2Manager.cs
  22. 43
      src/Avalonia.X11/XIStructs.cs

2
samples/BindingDemo/App.xaml.cs

@ -26,6 +26,6 @@ namespace BindingDemo
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug(); .LogToTrace();
} }
} }

2
samples/ControlCatalog.Desktop/Program.cs

@ -18,7 +18,7 @@ namespace ControlCatalog
/// </summary> /// </summary>
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.LogToDebug() .LogToTrace()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI(); .UseReactiveUI();

2
samples/ControlCatalog.NetCore/Program.cs

@ -121,7 +121,7 @@ namespace ControlCatalog.NetCore
.UseSkia() .UseSkia()
.UseReactiveUI() .UseReactiveUI()
.UseManagedSystemDialogs() .UseManagedSystemDialogs()
.LogToDebug(); .LogToTrace();
static void SilenceConsole() static void SilenceConsole()
{ {

2
samples/RenderDemo/App.xaml.cs

@ -33,6 +33,6 @@ namespace RenderDemo
}) })
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug(); .LogToTrace();
} }
} }

2
samples/Sandbox/Program.cs

@ -10,7 +10,7 @@ namespace Sandbox
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug() .LogToTrace()
.StartWithClassicDesktopLifetime(args); .StartWithClassicDesktopLifetime(args);
} }
} }

2
samples/VirtualizationDemo/Program.cs

@ -9,7 +9,7 @@ namespace VirtualizationDemo
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug(); .LogToTrace();
public static int Main(string[] args) public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);

3
src/Avalonia.Base/ApiCompatBaseline.txt

@ -1,3 +1,4 @@
Compat issues with assembly Avalonia.Base: Compat issues with assembly Avalonia.Base:
CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract. CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract.
Total Issues: 1 TypesMustExist : Type 'Avalonia.Logging.DebugLogSink' does not exist in the implementation but it does exist in the contract.
Total Issues: 2

14
src/Avalonia.Base/Logging/DebugLogSink.cs → src/Avalonia.Base/Logging/TraceLogSink.cs

@ -6,12 +6,12 @@ using Avalonia.Utilities;
namespace Avalonia.Logging namespace Avalonia.Logging
{ {
public class DebugLogSink : ILogSink public class TraceLogSink : ILogSink
{ {
private readonly LogEventLevel _level; private readonly LogEventLevel _level;
private readonly IList<string> _areas; private readonly IList<string> _areas;
public DebugLogSink( public TraceLogSink(
LogEventLevel minimumLevel, LogEventLevel minimumLevel,
IList<string> areas = null) IList<string> areas = null)
{ {
@ -28,7 +28,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format<object, object, object>(area, messageTemplate, source)); Trace.WriteLine(Format<object, object, object>(area, messageTemplate, source));
} }
} }
@ -36,7 +36,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0)); Trace.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0));
} }
} }
@ -44,7 +44,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1)); Trace.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1));
} }
} }
@ -52,7 +52,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2)); Trace.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2));
} }
} }
@ -60,7 +60,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format(area, messageTemplate, source, propertyValues)); Trace.WriteLine(Format(area, messageTemplate, source, propertyValues));
} }
} }

13
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -340,8 +340,6 @@ namespace Avalonia.Controls
if (OwningGrid != null && OwningGrid.ColumnHeaders != null) if (OwningGrid != null && OwningGrid.ColumnHeaders != null)
{ {
args.Pointer.Capture(this);
_dragMode = DragMode.MouseDown; _dragMode = DragMode.MouseDown;
_frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth(); _frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth();
_lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition); _lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition);
@ -413,8 +411,9 @@ namespace Avalonia.Controls
} }
//TODO DragEvents //TODO DragEvents
internal void OnMouseMove(ref bool handled, Point mousePosition, Point mousePositionHeaders) internal void OnMouseMove(PointerEventArgs args, Point mousePosition, Point mousePositionHeaders)
{ {
var handled = args.Handled;
if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null) if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null)
{ {
return; return;
@ -438,7 +437,10 @@ namespace Avalonia.Controls
} }
_lastMousePositionHeaders = mousePositionHeaders; _lastMousePositionHeaders = mousePositionHeaders;
if (args.Pointer.Captured != this)
args.Pointer.Capture(this);
SetDragCursor(mousePosition); SetDragCursor(mousePosition);
} }
@ -506,8 +508,7 @@ namespace Avalonia.Controls
Point mousePosition = e.GetPosition(this); Point mousePosition = e.GetPosition(this);
Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders); Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders);
bool handled = false; OnMouseMove(e, mousePosition, mousePositionHeaders);
OnMouseMove(ref handled, mousePosition, mousePositionHeaders);
} }
/// <summary> /// <summary>

13
src/Avalonia.Controls/ContextMenu.cs

@ -62,6 +62,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<Rect?> PlacementRectProperty = public static readonly StyledProperty<Rect?> PlacementRectProperty =
AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect)); AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
/// <summary>
/// Defines the <see cref="WindowManagerAddShadowHint"/> property.
/// </summary>
public static readonly StyledProperty<bool> WindowManagerAddShadowHintProperty =
Popup.WindowManagerAddShadowHintProperty.AddOwner<ContextMenu>();
/// <summary> /// <summary>
/// Defines the <see cref="PlacementTarget"/> property. /// Defines the <see cref="PlacementTarget"/> property.
/// </summary> /// </summary>
@ -158,6 +164,12 @@ namespace Avalonia.Controls
set { SetValue(PlacementModeProperty, value); } set { SetValue(PlacementModeProperty, value); }
} }
public bool WindowManagerAddShadowHint
{
get { return GetValue(WindowManagerAddShadowHintProperty); }
set { SetValue(WindowManagerAddShadowHintProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets the the anchor rectangle within the parent that the context menu will be placed /// Gets or sets the the anchor rectangle within the parent that the context menu will be placed
/// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>. /// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
@ -267,6 +279,7 @@ namespace Avalonia.Controls
PlacementTarget = PlacementTarget ?? control, PlacementTarget = PlacementTarget ?? control,
IsLightDismissEnabled = true, IsLightDismissEnabled = true,
OverlayDismissEventPassThrough = true, OverlayDismissEventPassThrough = true,
WindowManagerAddShadowHint = WindowManagerAddShadowHint,
}; };
_popup.Opened += PopupOpened; _popup.Opened += PopupOpened;

2
src/Avalonia.Controls/ItemsControl.cs

@ -169,7 +169,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="items">The collection.</param> /// <param name="items">The collection.</param>
/// <param name="index">The index.</param> /// <param name="index">The index.</param>
/// <returns>The index of the item or -1 if the item was not found.</returns> /// <returns>The item at the given index or null if the index is out of bounds.</returns>
protected static object ElementAt(IEnumerable items, int index) protected static object ElementAt(IEnumerable items, int index)
{ {
if (index != -1 && index < items.Count()) if (index != -1 && index < items.Count())

19
src/Avalonia.Controls/LoggingExtensions.cs

@ -1,25 +1,36 @@
using Avalonia.Controls; using System;
using Avalonia.Controls;
using Avalonia.Logging; using Avalonia.Logging;
namespace Avalonia namespace Avalonia
{ {
public static class LoggingExtensions public static class LoggingExtensions
{ {
[Obsolete("Use LogToTrace")]
public static T LogToDebug<T>(
this T builder,
LogEventLevel level = LogEventLevel.Warning,
params string[] areas)
where T : AppBuilderBase<T>, new()
{
return LogToTrace(builder, level, areas);
}
/// <summary> /// <summary>
/// Logs Avalonia events to the <see cref="System.Diagnostics.Debug"/> sink. /// Logs Avalonia events to the <see cref="System.Diagnostics.Trace"/> sink.
/// </summary> /// </summary>
/// <typeparam name="T">The application class type.</typeparam> /// <typeparam name="T">The application class type.</typeparam>
/// <param name="builder">The app builder instance.</param> /// <param name="builder">The app builder instance.</param>
/// <param name="level">The minimum level to log.</param> /// <param name="level">The minimum level to log.</param>
/// <param name="areas">The areas to log. Valid values are listed in <see cref="LogArea"/>.</param> /// <param name="areas">The areas to log. Valid values are listed in <see cref="LogArea"/>.</param>
/// <returns>The app builder instance.</returns> /// <returns>The app builder instance.</returns>
public static T LogToDebug<T>( public static T LogToTrace<T>(
this T builder, this T builder,
LogEventLevel level = LogEventLevel.Warning, LogEventLevel level = LogEventLevel.Warning,
params string[] areas) params string[] areas)
where T : AppBuilderBase<T>, new() where T : AppBuilderBase<T>, new()
{ {
Logger.Sink = new DebugLogSink(level, areas); Logger.Sink = new TraceLogSink(level, areas);
return builder; return builder;
} }
} }

7
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@ -512,6 +512,13 @@ namespace Avalonia.Controls.Presenters
var generator = Owner.ItemContainerGenerator; var generator = Owner.ItemContainerGenerator;
var newOffset = -1.0; var newOffset = -1.0;
//better not trigger any container generation/recycle while or layout stuff
//before panel is attached/visible
if (!panel.IsAttachedToVisualTree)
{
return null;
}
if (!panel.IsMeasureValid && panel.PreviousMeasure.HasValue) if (!panel.IsMeasureValid && panel.PreviousMeasure.HasValue)
{ {
//before any kind of scrolling we need to make sure panel measure is valid //before any kind of scrolling we need to make sure panel measure is valid

2
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -67,8 +67,6 @@ namespace Avalonia.Controls.Primitives
{ {
get get
{ {
if (IsPopup)
return null;
var rv = FindLayer<LightDismissOverlayLayer>(); var rv = FindLayer<LightDismissOverlayLayer>();
if (rv == null) if (rv == null)
{ {

20
src/Avalonia.Input/MouseDevice.cs

@ -19,6 +19,7 @@ namespace Avalonia.Input
private readonly Pointer _pointer; private readonly Pointer _pointer;
private bool _disposed; private bool _disposed;
private PixelPoint? _position;
public MouseDevice(Pointer? pointer = null) public MouseDevice(Pointer? pointer = null)
{ {
@ -39,10 +40,11 @@ namespace Avalonia.Input
/// <summary> /// <summary>
/// Gets the mouse position, in screen coordinates. /// Gets the mouse position, in screen coordinates.
/// </summary> /// </summary>
[Obsolete("Use events instead")]
public PixelPoint Position public PixelPoint Position
{ {
get; get => _position ?? new PixelPoint(-1, -1);
protected set; protected set => _position = value;
} }
/// <summary> /// <summary>
@ -91,7 +93,16 @@ namespace Avalonia.Input
public void SceneInvalidated(IInputRoot root, Rect rect) public void SceneInvalidated(IInputRoot root, Rect rect)
{ {
var clientPoint = root.PointToClient(Position); // Pointer is outside of the target area
if (_position == null )
{
if (root.PointerOverElement != null)
ClearPointerOver(this, 0, root, PointerPointProperties.None, KeyModifiers.None);
return;
}
var clientPoint = root.PointToClient(_position.Value);
if (rect.Contains(clientPoint)) if (rect.Contains(clientPoint))
{ {
@ -132,7 +143,7 @@ namespace Avalonia.Input
if(mouse._disposed) if(mouse._disposed)
return; return;
Position = e.Root.PointToScreen(e.Position); _position = e.Root.PointToScreen(e.Position);
var props = CreateProperties(e); var props = CreateProperties(e);
var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers); var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers);
switch (e.Type) switch (e.Type)
@ -176,6 +187,7 @@ namespace Avalonia.Input
device = device ?? throw new ArgumentNullException(nameof(device)); device = device ?? throw new ArgumentNullException(nameof(device));
root = root ?? throw new ArgumentNullException(nameof(root)); root = root ?? throw new ArgumentNullException(nameof(root));
_position = null;
ClearPointerOver(this, timestamp, root, properties, inputModifiers); ClearPointerOver(this, timestamp, root, properties, inputModifiers);
} }

1
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Avalonia.ReactiveUI</PackageId> <PackageId>Avalonia.ReactiveUI</PackageId>
<SignAssembly>True</SignAssembly>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" /> <ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />

4
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -2,6 +2,8 @@ Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.Geometry.GetRenderBounds(Avalonia.Media.Pen)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Boolean Avalonia.Media.Geometry.StrokeContains(Avalonia.Media.Pen, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
@ -34,4 +36,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalon
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public Avalonia.Utilities.IRef<Avalonia.Platform.IRenderTargetBitmapImpl> Avalonia.Rendering.RenderLayer.Bitmap.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Utilities.IRef<Avalonia.Platform.IRenderTargetBitmapImpl> Avalonia.Rendering.RenderLayer.Bitmap.get()' does not exist in the implementation but it does exist in the contract.
Total Issues: 35 Total Issues: 37

14
src/Avalonia.Visuals/Media/Drawing.cs

@ -1,11 +1,19 @@
using Avalonia.Platform; namespace Avalonia.Media
namespace Avalonia.Media
{ {
/// <summary>
/// Abstract class that describes a 2-D drawing.
/// </summary>
public abstract class Drawing : AvaloniaObject public abstract class Drawing : AvaloniaObject
{ {
/// <summary>
/// Draws this drawing to the given <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public abstract void Draw(DrawingContext context); public abstract void Draw(DrawingContext context);
/// <summary>
/// Gets the drawing's bounding rectangle.
/// </summary>
public abstract Rect GetBounds(); public abstract Rect GetBounds();
} }
} }

4
src/Avalonia.Visuals/Media/Geometry.cs

@ -84,7 +84,7 @@ namespace Avalonia.Media
/// </summary> /// </summary>
/// <param name="pen">The stroke thickness.</param> /// <param name="pen">The stroke thickness.</param>
/// <returns>The bounding rectangle.</returns> /// <returns>The bounding rectangle.</returns>
public Rect GetRenderBounds(Pen pen) => PlatformImpl?.GetRenderBounds(pen) ?? Rect.Empty; public Rect GetRenderBounds(IPen pen) => PlatformImpl?.GetRenderBounds(pen) ?? Rect.Empty;
/// <summary> /// <summary>
/// Indicates whether the geometry's fill contains the specified point. /// Indicates whether the geometry's fill contains the specified point.
@ -102,7 +102,7 @@ namespace Avalonia.Media
/// <param name="pen">The pen to use.</param> /// <param name="pen">The pen to use.</param>
/// <param name="point">The point.</param> /// <param name="point">The point.</param>
/// <returns><c>true</c> if the geometry contains the point; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if the geometry contains the point; otherwise, <c>false</c>.</returns>
public bool StrokeContains(Pen pen, Point point) public bool StrokeContains(IPen pen, Point point)
{ {
return PlatformImpl?.StrokeContains(pen, point) == true; return PlatformImpl?.StrokeContains(pen, point) == true;
} }

44
src/Avalonia.Visuals/Media/GeometryDrawing.cs

@ -1,12 +1,38 @@
using Avalonia.Metadata; using Avalonia.Media.Immutable;
using Avalonia.Metadata;
namespace Avalonia.Media namespace Avalonia.Media
{ {
/// <summary>
/// Represents a drawing operation that combines
/// a geometry with and brush and/or pen to produce rendered content.
/// </summary>
public class GeometryDrawing : Drawing public class GeometryDrawing : Drawing
{ {
// Adding the Pen's stroke thickness here could yield wrong results due to transforms.
private static readonly IPen s_boundsPen = new ImmutablePen(Colors.Black.ToUint32(), 0);
/// <summary>
/// Defines the <see cref="Geometry"/> property.
/// </summary>
public static readonly StyledProperty<Geometry> GeometryProperty = public static readonly StyledProperty<Geometry> GeometryProperty =
AvaloniaProperty.Register<GeometryDrawing, Geometry>(nameof(Geometry)); AvaloniaProperty.Register<GeometryDrawing, Geometry>(nameof(Geometry));
/// <summary>
/// Defines the <see cref="Brush"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
/// <summary>
/// Defines the <see cref="Pen"/> property.
/// </summary>
public static readonly StyledProperty<Pen> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen));
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.Geometry"/> that describes the shape of this <see cref="GeometryDrawing"/>.
/// </summary>
[Content] [Content]
public Geometry Geometry public Geometry Geometry
{ {
@ -14,18 +40,18 @@ namespace Avalonia.Media
set => SetValue(GeometryProperty, value); set => SetValue(GeometryProperty, value);
} }
public static readonly StyledProperty<IBrush> BrushProperty = /// <summary>
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent); /// Gets or sets the <see cref="Avalonia.Media.IBrush"/> used to fill the interior of the shape described by this <see cref="GeometryDrawing"/>.
/// </summary>
public IBrush Brush public IBrush Brush
{ {
get => GetValue(BrushProperty); get => GetValue(BrushProperty);
set => SetValue(BrushProperty, value); set => SetValue(BrushProperty, value);
} }
public static readonly StyledProperty<Pen> PenProperty = /// <summary>
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen)); /// Gets or sets the <see cref="Avalonia.Media.IPen"/> used to stroke this <see cref="GeometryDrawing"/>.
/// </summary>
public IPen Pen public IPen Pen
{ {
get => GetValue(PenProperty); get => GetValue(PenProperty);
@ -42,9 +68,7 @@ namespace Avalonia.Media
public override Rect GetBounds() public override Rect GetBounds()
{ {
// adding the Pen's stroke thickness here could yield wrong results due to transforms return Geometry?.GetRenderBounds(s_boundsPen) ?? Rect.Empty;
var pen = new Pen(Brushes.Black, 0);
return Geometry?.GetRenderBounds(pen) ?? new Rect();
} }
} }
} }

84
src/Avalonia.X11/XI2Manager.cs

@ -13,7 +13,10 @@ namespace Avalonia.X11
{ {
XiEventType.XI_Motion, XiEventType.XI_Motion,
XiEventType.XI_ButtonPress, XiEventType.XI_ButtonPress,
XiEventType.XI_ButtonRelease XiEventType.XI_ButtonRelease,
XiEventType.XI_Leave,
XiEventType.XI_Enter,
}; };
private static readonly XiEventType[] MultiTouchEventTypes = new XiEventType[] private static readonly XiEventType[] MultiTouchEventTypes = new XiEventType[]
@ -162,7 +165,9 @@ namespace Avalonia.X11
| XEventMask.Button4MotionMask | XEventMask.Button4MotionMask
| XEventMask.Button5MotionMask | XEventMask.Button5MotionMask
| XEventMask.ButtonPressMask | XEventMask.ButtonPressMask
| XEventMask.ButtonReleaseMask; | XEventMask.ButtonReleaseMask
| XEventMask.LeaveWindowMask
| XEventMask.EnterWindowMask;
} }
public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid); public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid);
@ -175,14 +180,39 @@ namespace Avalonia.X11
_pointerDevice.Update(changed->Classes, changed->NumClasses); _pointerDevice.Update(changed->Classes, changed->NumClasses);
} }
if ((xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion) if ((xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion)
|| (xev->evtype>=XiEventType.XI_TouchBegin&&xev->evtype<=XiEventType.XI_TouchEnd)) || (xev->evtype >= XiEventType.XI_TouchBegin && xev->evtype <= XiEventType.XI_TouchEnd))
{ {
var dev = (XIDeviceEvent*)xev; var dev = (XIDeviceEvent*)xev;
if (_clients.TryGetValue(dev->EventWindow, out var client)) if (_clients.TryGetValue(dev->EventWindow, out var client))
OnDeviceEvent(client, new ParsedDeviceEvent(dev)); OnDeviceEvent(client, new ParsedDeviceEvent(dev));
} }
if (xev->evtype == XiEventType.XI_Leave || xev->evtype == XiEventType.XI_Enter)
{
var rev = (XIEnterLeaveEvent*)xev;
if (_clients.TryGetValue(rev->EventWindow, out var client))
OnEnterLeaveEvent(client, ref *rev);
}
}
void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
{
if (ev.evtype == XiEventType.XI_Leave)
{
var buttons = ParsedDeviceEvent.ParseButtonState(ev.buttons.MaskLen, ev.buttons.Mask);
var detail = ev.detail;
if ((detail == XiEnterLeaveDetail.XINotifyNonlinearVirtual ||
detail == XiEnterLeaveDetail.XINotifyNonlinear ||
detail == XiEnterLeaveDetail.XINotifyVirtual)
&& buttons == default)
{
client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, (ulong)ev.time.ToInt64(),
client.InputRoot,
RawPointerEventType.LeaveWindow, new Point(ev.event_x, ev.event_y), buttons));
}
}
} }
void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev) void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
@ -284,6 +314,29 @@ namespace Avalonia.X11
public int Detail { get; set; } public int Detail { get; set; }
public bool Emulated { get; set; } public bool Emulated { get; set; }
public Dictionary<int, double> Valuators { get; } public Dictionary<int, double> Valuators { get; }
public static RawInputModifiers ParseButtonState(int len, byte* buttons)
{
RawInputModifiers rv = default;
if (len > 0)
{
if (XIMaskIsSet(buttons, 1))
rv |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
rv |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
rv |= RawInputModifiers.RightMouseButton;
if (len > 1)
{
if (XIMaskIsSet(buttons, 8))
rv |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
rv |= RawInputModifiers.XButton2MouseButton;
}
}
return rv;
}
public ParsedDeviceEvent(XIDeviceEvent* ev) public ParsedDeviceEvent(XIDeviceEvent* ev)
{ {
Type = ev->evtype; Type = ev->evtype;
@ -298,27 +351,16 @@ namespace Avalonia.X11
if (state.HasFlag(XModifierMask.Mod4Mask)) if (state.HasFlag(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta; Modifiers |= RawInputModifiers.Meta;
if (ev->buttons.MaskLen > 0) Modifiers = ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
{
var buttons = ev->buttons.Mask;
if (XIMaskIsSet(buttons, 1))
Modifiers |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
Modifiers |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
Modifiers |= RawInputModifiers.RightMouseButton;
if (XIMaskIsSet(buttons, 8))
Modifiers |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
Modifiers |= RawInputModifiers.XButton2MouseButton;
}
Valuators = new Dictionary<int, double>(); Valuators = new Dictionary<int, double>();
Position = new Point(ev->event_x, ev->event_y); Position = new Point(ev->event_x, ev->event_y);
var values = ev->valuators.Values; var values = ev->valuators.Values;
for (var c = 0; c < ev->valuators.MaskLen * 8; c++) if(ev->valuators.Mask != null)
if (XIMaskIsSet(ev->valuators.Mask, c)) for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
Valuators[c] = *values++; if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease) if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease)
Button = ev->detail; Button = ev->detail;
Detail = ev->detail; Detail = ev->detail;

43
src/Avalonia.X11/XIStructs.cs

@ -236,6 +236,34 @@ namespace Avalonia.X11
public XIModifierState mods; public XIModifierState mods;
public XIModifierState group; public XIModifierState group;
} }
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIEnterLeaveEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
public Bool send_event; /* true if this came from a SendEvent request */
public IntPtr display; /* Display the event was read from */
public int extension; /* XI extension offset */
public XiEventType evtype;
public IntPtr time;
public int deviceid;
public int sourceid;
public XiEnterLeaveDetail detail;
public IntPtr RootWindow;
public IntPtr EventWindow;
public IntPtr ChildWindow;
public double root_x;
public double root_y;
public double event_x;
public double event_y;
public int mode;
public int focus;
public int same_screen;
public XIButtonState buttons;
public XIModifierState mods;
public XIModifierState group;
}
[Flags] [Flags]
public enum XiDeviceEventFlags : int public enum XiDeviceEventFlags : int
@ -286,5 +314,18 @@ namespace Avalonia.X11
XI_BarrierLeave = 26, XI_BarrierLeave = 26,
XI_LASTEVENT = XI_BarrierLeave, XI_LASTEVENT = XI_BarrierLeave,
} }
enum XiEnterLeaveDetail
{
XINotifyAncestor = 0,
XINotifyVirtual = 1,
XINotifyInferior = 2,
XINotifyNonlinear = 3,
XINotifyNonlinearVirtual = 4,
XINotifyPointer = 5,
XINotifyPointerRoot = 6,
XINotifyDetailNone = 7
}
} }

Loading…
Cancel
Save