From 30fd91121e638e0a835a305993793b4e709db51c Mon Sep 17 00:00:00 2001 From: robloo Date: Sat, 8 Oct 2022 14:43:02 -0400 Subject: [PATCH 01/32] Comment and update the Screen class --- samples/ControlCatalog/Pages/ScreenPage.cs | 2 +- src/Avalonia.Controls/Platform/Screen.cs | 25 ++++++++++++++++++++-- src/Avalonia.Controls/Screens.cs | 16 +++++++++++++- src/Avalonia.X11/X11Screens.cs | 8 +++---- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 +- 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index 823f59e030..6a4ed5a890 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -65,7 +65,7 @@ namespace ControlCatalog.Pages formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); - formattedText = CreateFormattedText($"Primary: {screen.Primary}"); + formattedText = CreateFormattedText($"Primary: {screen.IsPrimary}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); formattedText = diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs index 976faed3fd..0f287fd5da 100644 --- a/src/Avalonia.Controls/Platform/Screen.cs +++ b/src/Avalonia.Controls/Platform/Screen.cs @@ -1,21 +1,42 @@ namespace Avalonia.Platform { + /// + /// Represents a single display screen. + /// public class Screen { + /// + /// Gets the pixel density of the screen. + /// This is a scaling factor so multiply by 100 to get a percentage. + /// + /// + /// Both X and Y density are assumed uniform. + /// public double PixelDensity { get; } + /// + /// Gets the overall pixel-size of the screen. + /// This generally is the raw pixel counts in both the X and Y direction. + /// public PixelRect Bounds { get; } + /// + /// Gets the actual working-area pixel-size of the screen. + /// This may be smaller to account for notches and other block-out areas. + /// public PixelRect WorkingArea { get; } - public bool Primary { get; } + /// + /// Gets a value indicating whether the screen is the primary one. + /// + public bool IsPrimary { get; } public Screen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool primary) { this.PixelDensity = pixelDensity; this.Bounds = bounds; this.WorkingArea = workingArea; - this.Primary = primary; + this.IsPrimary = primary; } } } diff --git a/src/Avalonia.Controls/Screens.cs b/src/Avalonia.Controls/Screens.cs index a554f82f61..da37959402 100644 --- a/src/Avalonia.Controls/Screens.cs +++ b/src/Avalonia.Controls/Screens.cs @@ -8,13 +8,27 @@ using Avalonia.VisualTree; namespace Avalonia.Controls { + /// + /// Represents all screens available on a device. + /// public class Screens { private readonly IScreenImpl _iScreenImpl; + /// + /// Gets the total number of screens available on this device. + /// public int ScreenCount => _iScreenImpl?.ScreenCount ?? 0; + + /// + /// Gets the list of all screens available on this device. + /// public IReadOnlyList All => _iScreenImpl?.AllScreens ?? Array.Empty(); - public Screen? Primary => All.FirstOrDefault(x => x.Primary); + + /// + /// Gets the primary screen on this device. + /// + public Screen? Primary => All.FirstOrDefault(x => x.IsPrimary); public Screens(IScreenImpl iScreenImpl) { diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index bcaafb6a53..a65f09ee63 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -9,7 +9,7 @@ using JetBrains.Annotations; namespace Avalonia.X11 { - class X11Screens : IScreenImpl + class X11Screens : IScreenImpl { private IX11Screens _impl; @@ -218,7 +218,7 @@ namespace Avalonia.X11 public int ScreenCount => _impl.Screens.Length; public IReadOnlyList AllScreens => - _impl.Screens.Select(s => new Screen(s.PixelDensity, s.Bounds, s.WorkingArea, s.Primary)).ToArray(); + _impl.Screens.Select(s => new Screen(s.PixelDensity, s.Bounds, s.WorkingArea, s.IsPrimary)).ToArray(); } interface IX11Screens @@ -281,7 +281,7 @@ namespace Avalonia.X11 { private const int FullHDWidth = 1920; private const int FullHDHeight = 1080; - public bool Primary { get; } + public bool IsPrimary { get; } public string Name { get; set; } public PixelRect Bounds { get; set; } public Size? PhysicalSize { get; set; } @@ -291,7 +291,7 @@ namespace Avalonia.X11 public X11Screen(PixelRect bounds, bool primary, string name, Size? physicalSize, double? pixelDensity) { - Primary = primary; + IsPrimary = primary; Name = name; Bounds = bounds; if (physicalSize == null && pixelDensity == null) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0f243fcf9f..9741f3f804 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -224,7 +224,7 @@ namespace Avalonia.Win32 } } - private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.Primary)?.PixelDensity ?? 1; + private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.PixelDensity ?? 1; public double RenderScaling => _scaling; From 31a15075ed6947e6f7998279d6daf59438304728 Mon Sep 17 00:00:00 2001 From: robloo Date: Sat, 8 Oct 2022 14:47:26 -0400 Subject: [PATCH 02/32] Rename missed parameter --- src/Avalonia.Controls/Platform/Screen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs index 0f287fd5da..cdab81705f 100644 --- a/src/Avalonia.Controls/Platform/Screen.cs +++ b/src/Avalonia.Controls/Platform/Screen.cs @@ -31,12 +31,12 @@ /// public bool IsPrimary { get; } - public Screen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool primary) + public Screen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool isPrimary) { this.PixelDensity = pixelDensity; this.Bounds = bounds; this.WorkingArea = workingArea; - this.IsPrimary = primary; + this.IsPrimary = isPrimary; } } } From f91a788d18a40c187cd09e3516d86619869429c4 Mon Sep 17 00:00:00 2001 From: dif-sam <41672086+dif-sam@users.noreply.github.com> Date: Thu, 13 Oct 2022 16:21:54 +0400 Subject: [PATCH 03/32] Suggested fix for #9173 trying to deffere request for BringIntoView, when TreeViewItem not ready yet. --- src/Avalonia.Controls/TreeViewItem.cs | 29 +++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index ada081b808..c2304abbc8 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -45,6 +45,8 @@ namespace Avalonia.Controls private IControl? _header; private bool _isExpanded; private int _level; + private bool _templateApplied; + private bool _deferredBringIntoViewFlag; /// /// Initializes static members of the class. @@ -136,15 +138,24 @@ namespace Avalonia.Controls protected virtual void OnRequestBringIntoView(RequestBringIntoViewEventArgs e) { - if (e.TargetObject == this && _header != null) + if (e.TargetObject == this) { - var m = _header.TransformToVisual(this); + if (!_templateApplied) + { + _deferredBringIntoViewFlag = true; + return; + } - if (m.HasValue) + if (_header != null) { - var bounds = new Rect(_header.Bounds.Size); - var rect = bounds.TransformToAABB(m.Value); - e.TargetRect = rect; + var m = _header.TransformToVisual(this); + + if (m.HasValue) + { + var bounds = new Rect(_header.Bounds.Size); + var rect = bounds.TransformToAABB(m.Value); + e.TargetRect = rect; + } } } } @@ -187,6 +198,12 @@ namespace Avalonia.Controls protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { _header = e.NameScope.Find("PART_Header"); + _templateApplied = true; + if (_deferredBringIntoViewFlag) + { + _deferredBringIntoViewFlag = false; + Dispatcher.UIThread.Post(this.BringIntoView); // must use the Dispatcher, otherwise the TreeView doesn't scroll + } } private static int CalculateDistanceFromLogicalParent(ILogical? logical, int @default = -1) where T : class From 65d39603fac9f963324158ab8d7c420565c5785b Mon Sep 17 00:00:00 2001 From: dif-sam <41672086+dif-sam@users.noreply.github.com> Date: Thu, 13 Oct 2022 16:55:55 +0400 Subject: [PATCH 04/32] Forgotten namespase added to usings --- src/Avalonia.Controls/TreeViewItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs index c2304abbc8..2f96e6911f 100644 --- a/src/Avalonia.Controls/TreeViewItem.cs +++ b/src/Avalonia.Controls/TreeViewItem.cs @@ -6,6 +6,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.LogicalTree; +using Avalonia.Threading; namespace Avalonia.Controls { From cc915f888cca167e32157f66a81654c8959e1374 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 16 Oct 2022 16:31:00 +0200 Subject: [PATCH 05/32] fix: Under Windows - Arithmetic operation resulted in an overflow. --- src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 9d1920498b..f28f4fd740 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1877,7 +1877,7 @@ namespace Avalonia.Win32.Interop public static uint LGID(IntPtr HKL) { - return (uint)(HKL.ToInt32() & 0xffff); + return (uint)(HKL.ToInt64() & 0xffff); } public const int SORT_DEFAULT = 0; From 6bc689a662cd9f8154fed77fd6aa13e494cbb3ad Mon Sep 17 00:00:00 2001 From: robloo Date: Tue, 18 Oct 2022 21:10:59 -0400 Subject: [PATCH 06/32] Updates from code review --- samples/ControlCatalog/Pages/ScreenPage.cs | 2 +- src/Avalonia.Controls/Platform/Screen.cs | 35 +++++++++++++++------- src/Avalonia.Native/WindowImplBase.cs | 2 +- src/Avalonia.X11/X11Window.cs | 2 +- src/Windows/Avalonia.Win32/TrayIconImpl.cs | 8 ++--- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 +- 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index 6a4ed5a890..119bc09888 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -62,7 +62,7 @@ namespace ControlCatalog.Pages CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20)); - formattedText = CreateFormattedText($"Scaling: {screen.PixelDensity * 100}%"); + formattedText = CreateFormattedText($"Scaling: {screen.Scale * 100}%"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); formattedText = CreateFormattedText($"Primary: {screen.IsPrimary}"); diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs index cdab81705f..e5b8ca5555 100644 --- a/src/Avalonia.Controls/Platform/Screen.cs +++ b/src/Avalonia.Controls/Platform/Screen.cs @@ -1,4 +1,6 @@ -namespace Avalonia.Platform +using System; + +namespace Avalonia.Platform { /// /// Represents a single display screen. @@ -6,34 +8,47 @@ public class Screen { /// - /// Gets the pixel density of the screen. - /// This is a scaling factor so multiply by 100 to get a percentage. + /// Gets the scaling factor applied to the screen by the operating system. /// /// - /// Both X and Y density are assumed uniform. + /// Multiply this value by 100 to get a percentage. + /// Both X and Y scaling factors are assumed uniform. /// - public double PixelDensity { get; } + public double Scale { get; } + + /// + [Obsolete("Use the Scale property instead.")] + public double PixelDensity => Scale; /// /// Gets the overall pixel-size of the screen. - /// This generally is the raw pixel counts in both the X and Y direction. /// + /// + /// This generally is the raw pixel counts in both the X and Y direction. + /// public PixelRect Bounds { get; } /// /// Gets the actual working-area pixel-size of the screen. - /// This may be smaller to account for notches and other block-out areas. /// + /// + /// This area may be smaller than to account for notches and + /// other block-out areas such as taskbars etc. + /// public PixelRect WorkingArea { get; } /// /// Gets a value indicating whether the screen is the primary one. /// public bool IsPrimary { get; } - - public Screen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool isPrimary) + + /// + [Obsolete("Use the IsPrimary property instead.")] + public bool Primary => IsPrimary; + + public Screen(double scale, PixelRect bounds, PixelRect workingArea, bool isPrimary) { - this.PixelDensity = pixelDensity; + this.Scale = scale; this.Bounds = bounds; this.WorkingArea = workingArea; this.IsPrimary = isPrimary; diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 34de439c94..8bb2b0a713 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -92,7 +92,7 @@ namespace Avalonia.Native _savedScaling = RenderScaling; _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); - var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) + var monitor = Screen.AllScreens.OrderBy(x => x.Scale) .FirstOrDefault(m => m.Bounds.Contains(Position)); Resize(new Size(monitor.WorkingArea.Width * 0.75d, monitor.WorkingArea.Height * 0.7d), PlatformResizeReason.Layout); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index f24c33cafa..75b741ac77 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -120,7 +120,7 @@ namespace Avalonia.X11 if (!_popup && Screen != null) { - var monitor = Screen.AllScreens.OrderBy(x => x.PixelDensity) + var monitor = Screen.AllScreens.OrderBy(x => x.Scale) .FirstOrDefault(m => m.Bounds.Contains(Position)); if (monitor != null) diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs index 346d6e5adb..93bdfda652 100644 --- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs +++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs @@ -216,7 +216,7 @@ namespace Avalonia.Win32 { Anchor = PopupAnchor.TopLeft, Gravity = PopupGravity.BottomRight, - AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.PixelDensity, new Size(1, 1)), + AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.Scale, new Size(1, 1)), Size = finalRect.Size, ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY, }); @@ -244,16 +244,16 @@ namespace Avalonia.Win32 { var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft; var size = _hiddenWindow.Screens.Primary.Bounds.Size; - return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.PixelDensity, size.Height * _hiddenWindow.Screens.Primary.PixelDensity); + return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.Scale, size.Height * _hiddenWindow.Screens.Primary.Scale); } } public void MoveAndResize(Point devicePoint, Size virtualSize) { - _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.PixelDensity); + _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.Scale); } - public double Scaling => _hiddenWindow.Screens.Primary.PixelDensity; + public double Scaling => _hiddenWindow.Screens.Primary.Scale; } } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 9741f3f804..cd8515eaa6 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -224,7 +224,7 @@ namespace Avalonia.Win32 } } - private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.PixelDensity ?? 1; + private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.Scale ?? 1; public double RenderScaling => _scaling; From f271654d64885ffae707bf00e7b787a1ec39c62a Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 19 Oct 2022 09:49:06 +0200 Subject: [PATCH 07/32] fix: CS8350 --- src/Avalonia.Base/Media/PathMarkupParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Media/PathMarkupParser.cs b/src/Avalonia.Base/Media/PathMarkupParser.cs index 30c5206125..cf12bf5126 100644 --- a/src/Avalonia.Base/Media/PathMarkupParser.cs +++ b/src/Avalonia.Base/Media/PathMarkupParser.cs @@ -188,7 +188,7 @@ namespace Avalonia.Media _isOpen = true; } - private void SetFillRule(ref ReadOnlySpan span) + private void SetFillRule(scoped ref ReadOnlySpan span) { ThrowIfDisposed(); @@ -452,7 +452,7 @@ namespace Avalonia.Media return !span.IsEmpty && (span[0] == ',' || span[0] == '-' || span[0] == '.' || char.IsDigit(span[0])); } - private static bool ReadArgument(ref ReadOnlySpan remaining, out ReadOnlySpan argument) + private static bool ReadArgument(scoped ref ReadOnlySpan remaining, out ReadOnlySpan argument) { remaining = SkipWhitespace(remaining); if (remaining.IsEmpty) From 48bd894e6059f9c2062e5a35ccc5afc134cdeb25 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 19 Oct 2022 18:00:25 +0600 Subject: [PATCH 08/32] Use MicroCom.Runtime from nuget --- .../Avalonia.MicroCom.csproj | 1 + src/Avalonia.MicroCom/CallbackBase.cs | 4 +- .../IMicroComExceptionCallback.cs | 9 - .../IMicroComShadowContainer.cs | 9 - src/Avalonia.MicroCom/IUnknown.cs | 8 - src/Avalonia.MicroCom/LocalInterop.cs | 17 -- src/Avalonia.MicroCom/MicroComProxyBase.cs | 110 ----------- src/Avalonia.MicroCom/MicroComRuntime.cs | 143 -------------- src/Avalonia.MicroCom/MicroComShadow.cs | 177 ------------------ src/Avalonia.MicroCom/MicroComVtblBase.cs | 47 ----- src/Avalonia.Native/Avalonia.Native.csproj | 1 - src/Avalonia.Native/AvaloniaNativePlatform.cs | 1 + src/Avalonia.Native/CallbackBase.cs | 1 + src/Avalonia.Native/NativeControlHostImpl.cs | 1 + .../Avalonia.Win32/Avalonia.Win32.csproj | 1 - src/Windows/Avalonia.Win32/ClipboardImpl.cs | 7 +- src/Windows/Avalonia.Win32/DragSource.cs | 5 +- .../Interop/UnmanagedMethods.cs | 1 + src/Windows/Avalonia.Win32/OleContext.cs | 3 +- src/Windows/Avalonia.Win32/OleDataObject.cs | 2 +- src/Windows/Avalonia.Win32/OleDropTarget.cs | 1 + .../Avalonia.Win32/Win32StorageProvider.cs | 1 + .../Composition/WinUICompositedWindow.cs | 1 + .../Composition/WinUICompositorConnection.cs | 1 + .../WinRT/Composition/WinUIEffectBase.cs | 1 + .../WinUiCompositedWindowSurface.cs | 1 + .../WinRT/NativeWinRTMethods.cs | 1 + .../Avalonia.Win32/WinRT/WinRTInspectable.cs | 1 + 28 files changed, 26 insertions(+), 530 deletions(-) delete mode 100644 src/Avalonia.MicroCom/IMicroComExceptionCallback.cs delete mode 100644 src/Avalonia.MicroCom/IMicroComShadowContainer.cs delete mode 100644 src/Avalonia.MicroCom/IUnknown.cs delete mode 100644 src/Avalonia.MicroCom/LocalInterop.cs delete mode 100644 src/Avalonia.MicroCom/MicroComProxyBase.cs delete mode 100644 src/Avalonia.MicroCom/MicroComRuntime.cs delete mode 100644 src/Avalonia.MicroCom/MicroComShadow.cs delete mode 100644 src/Avalonia.MicroCom/MicroComVtblBase.cs diff --git a/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj b/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj index d7f39f6642..43ae612699 100644 --- a/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj +++ b/src/Avalonia.MicroCom/Avalonia.MicroCom.csproj @@ -7,6 +7,7 @@ <_AvaloniaPatchComInterop>true + false all diff --git a/src/Avalonia.MicroCom/CallbackBase.cs b/src/Avalonia.MicroCom/CallbackBase.cs index 6783ebe3dc..49d589a5fc 100644 --- a/src/Avalonia.MicroCom/CallbackBase.cs +++ b/src/Avalonia.MicroCom/CallbackBase.cs @@ -1,4 +1,6 @@ -namespace Avalonia.MicroCom +using MicroCom.Runtime; + +namespace Avalonia.MicroCom { public abstract class CallbackBase : IUnknown, IMicroComShadowContainer { diff --git a/src/Avalonia.MicroCom/IMicroComExceptionCallback.cs b/src/Avalonia.MicroCom/IMicroComExceptionCallback.cs deleted file mode 100644 index 08f20339ec..0000000000 --- a/src/Avalonia.MicroCom/IMicroComExceptionCallback.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Avalonia.MicroCom -{ - public interface IMicroComExceptionCallback - { - void RaiseException(Exception e); - } -} diff --git a/src/Avalonia.MicroCom/IMicroComShadowContainer.cs b/src/Avalonia.MicroCom/IMicroComShadowContainer.cs deleted file mode 100644 index a33d3a9811..0000000000 --- a/src/Avalonia.MicroCom/IMicroComShadowContainer.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Avalonia.MicroCom -{ - public interface IMicroComShadowContainer - { - MicroComShadow Shadow { get; set; } - void OnReferencedFromNative(); - void OnUnreferencedFromNative(); - } -} diff --git a/src/Avalonia.MicroCom/IUnknown.cs b/src/Avalonia.MicroCom/IUnknown.cs deleted file mode 100644 index 0dc4106423..0000000000 --- a/src/Avalonia.MicroCom/IUnknown.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Avalonia.MicroCom -{ - public interface IUnknown : IDisposable - { - } -} diff --git a/src/Avalonia.MicroCom/LocalInterop.cs b/src/Avalonia.MicroCom/LocalInterop.cs deleted file mode 100644 index 785f4e03a5..0000000000 --- a/src/Avalonia.MicroCom/LocalInterop.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Avalonia.MicroCom -{ - unsafe class LocalInterop - { - public static unsafe void CalliStdCallvoid(void* thisObject, void* methodPtr) - { - throw null; - } - - public static unsafe int CalliStdCallint(void* thisObject, Guid* guid, IntPtr* ppv, void* methodPtr) - { - throw null; - } - } -} diff --git a/src/Avalonia.MicroCom/MicroComProxyBase.cs b/src/Avalonia.MicroCom/MicroComProxyBase.cs deleted file mode 100644 index fe8a2bf9cf..0000000000 --- a/src/Avalonia.MicroCom/MicroComProxyBase.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Runtime.ConstrainedExecution; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Avalonia.MicroCom -{ - public unsafe class MicroComProxyBase : CriticalFinalizerObject, IUnknown - { - private IntPtr _nativePointer; - private bool _ownsHandle; - private SynchronizationContext _synchronizationContext; - - public IntPtr NativePointer - { - get - { - if (_nativePointer == IntPtr.Zero) - throw new ObjectDisposedException(this.GetType().FullName); - return _nativePointer; - } - } - - public void*** PPV => (void***)NativePointer; - - public MicroComProxyBase(IntPtr nativePointer, bool ownsHandle) - { - _nativePointer = nativePointer; - _ownsHandle = ownsHandle; - _synchronizationContext = SynchronizationContext.Current; - if(!_ownsHandle) - GC.SuppressFinalize(this); - } - - protected virtual int VTableSize => 3; - - public void AddRef() - { - LocalInterop.CalliStdCallvoid(PPV, (*PPV)[1]); - } - - public void Release() - { - LocalInterop.CalliStdCallvoid(PPV, (*PPV)[2]); - } - - public int QueryInterface(Guid guid, out IntPtr ppv) - { - IntPtr r = default; - var rv = LocalInterop.CalliStdCallint(PPV, &guid, &r, (*PPV)[0]); - ppv = r; - return rv; - } - - public T QueryInterface() where T : IUnknown - { - var guid = MicroComRuntime.GetGuidFor(typeof(T)); - var rv = QueryInterface(guid, out var ppv); - if (rv == 0) - return (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true); - throw new COMException("QueryInterface failed", rv); - } - - public bool IsDisposed => _nativePointer == IntPtr.Zero; - - protected virtual void Dispose(bool disposing) - { - if(_nativePointer == IntPtr.Zero) - return; - if (_ownsHandle) - { - Release(); - _ownsHandle = false; - } - _nativePointer = IntPtr.Zero; - GC.SuppressFinalize(this); - } - - public void Dispose() => Dispose(true); - - public bool OwnsHandle => _ownsHandle; - - public void EnsureOwned() - { - if (!_ownsHandle) - { - GC.ReRegisterForFinalize(true); - AddRef(); - _ownsHandle = true; - } - } - - private static readonly SendOrPostCallback _disposeDelegate = DisposeOnContext; - - private static void DisposeOnContext(object state) - { - (state as MicroComProxyBase)?.Dispose(false); - } - - ~MicroComProxyBase() - { - if(!_ownsHandle) - return; - if (_synchronizationContext == null) - Dispose(); - else - _synchronizationContext.Post(_disposeDelegate, this); - } - } -} diff --git a/src/Avalonia.MicroCom/MicroComRuntime.cs b/src/Avalonia.MicroCom/MicroComRuntime.cs deleted file mode 100644 index b9a56a69ba..0000000000 --- a/src/Avalonia.MicroCom/MicroComRuntime.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Runtime.InteropServices; - -namespace Avalonia.MicroCom -{ - public static unsafe class MicroComRuntime - { - private static ConcurrentDictionary _vtables = new ConcurrentDictionary(); - - private static ConcurrentDictionary> _factories = - new ConcurrentDictionary>(); - private static ConcurrentDictionary _guids = new ConcurrentDictionary(); - private static ConcurrentDictionary _guidsToTypes = new ConcurrentDictionary(); - - internal static readonly Guid ManagedObjectInterfaceGuid = Guid.Parse("cd7687c0-a9c2-4563-b08e-a399df50c633"); - - static MicroComRuntime() - { - Register(typeof(IUnknown), new Guid("00000000-0000-0000-C000-000000000046"), - (ppv, owns) => new MicroComProxyBase(ppv, owns)); - RegisterVTable(typeof(IUnknown), MicroComVtblBase.Vtable); - } - - public static void RegisterVTable(Type t, IntPtr vtable) - { - _vtables[t] = vtable; - } - - public static void Register(Type t, Guid guid, Func proxyFactory) - { - _factories[t] = proxyFactory; - _guids[t] = guid; - _guidsToTypes[guid] = t; - } - - public static Guid GetGuidFor(Type type) => _guids[type]; - - public static T CreateProxyFor(void* pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle); - public static T CreateProxyFor(IntPtr pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), pObject, ownsHandle); - - public static T CreateProxyOrNullFor(void* pObject, bool ownsHandle) where T : class => - pObject == null ? null : (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle); - - public static T CreateProxyOrNullFor(IntPtr pObject, bool ownsHandle) where T : class => - pObject == IntPtr.Zero ? null : (T)CreateProxyFor(typeof(T), pObject, ownsHandle); - - public static object CreateProxyFor(Type type, IntPtr pObject, bool ownsHandle) => _factories[type](pObject, ownsHandle); - - public static IntPtr GetNativeIntPtr(this T obj, bool owned = false) where T : IUnknown - => new IntPtr(GetNativePointer(obj, owned)); - public static void* GetNativePointer(T obj, bool owned = false) where T : IUnknown - { - if (obj == null) - return null; - if (obj is MicroComProxyBase proxy) - { - if(owned) - proxy.AddRef(); - return (void*)proxy.NativePointer; - } - - if (obj is IMicroComShadowContainer container) - { - container.Shadow ??= new MicroComShadow(container); - void* ptr = null; - var res = container.Shadow.GetOrCreateNativePointer(typeof(T), &ptr); - if (res != 0) - throw new COMException( - "Unable to create native callable wrapper for type " + typeof(T) + " for instance of type " + - obj.GetType(), - res); - if (owned) - container.Shadow.AddRef((Ccw*)ptr); - return ptr; - } - throw new ArgumentException("Unable to get a native pointer for " + obj); - } - - public static object GetObjectFromCcw(IntPtr ccw) - { - var ptr = (Ccw*)ccw; - var shadow = (MicroComShadow)GCHandle.FromIntPtr(ptr->GcShadowHandle).Target; - return shadow.Target; - } - - public static bool IsComWrapper(IUnknown obj) => obj is MicroComProxyBase; - - public static object TryUnwrapManagedObject(IUnknown obj) - { - if (obj is not MicroComProxyBase proxy) - return null; - if (proxy.QueryInterface(ManagedObjectInterfaceGuid, out _) != 0) - return null; - // Successful QueryInterface always increments ref counter - proxy.Release(); - return GetObjectFromCcw(proxy.NativePointer); - } - - public static bool TryGetTypeForGuid(Guid guid, out Type t) => _guidsToTypes.TryGetValue(guid, out t); - - public static bool GetVtableFor(Type type, out IntPtr ptr) => _vtables.TryGetValue(type, out ptr); - - public static void UnhandledException(object target, Exception e) - { - if (target is IMicroComExceptionCallback cb) - { - try - { - cb.RaiseException(e); - } - catch - { - // We've tried - } - } - - } - - public static T CloneReference(this T iface) where T : IUnknown - { - var proxy = (MicroComProxyBase)(object)iface; - var ownedPointer = GetNativePointer(iface, true); - return CreateProxyFor(ownedPointer, true); - } - - public static T QueryInterface(this IUnknown unknown) where T : IUnknown - { - var proxy = (MicroComProxyBase)unknown; - return proxy.QueryInterface(); - } - - public static void UnsafeAddRef(this IUnknown unknown) - { - ((MicroComProxyBase)unknown).AddRef(); - } - - public static void UnsafeRelease(this IUnknown unknown) - { - ((MicroComProxyBase)unknown).Release(); - } - } -} diff --git a/src/Avalonia.MicroCom/MicroComShadow.cs b/src/Avalonia.MicroCom/MicroComShadow.cs deleted file mode 100644 index 765ff3b9ad..0000000000 --- a/src/Avalonia.MicroCom/MicroComShadow.cs +++ /dev/null @@ -1,177 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Threading; - -namespace Avalonia.MicroCom -{ - public unsafe class MicroComShadow : IDisposable - { - private readonly object _lock = new object(); - private readonly Dictionary _shadows = new Dictionary(); - private readonly Dictionary _backShadows = new Dictionary(); - private GCHandle? _handle; - private volatile int _refCount; - internal IMicroComShadowContainer Target { get; } - internal MicroComShadow(IMicroComShadowContainer target) - { - Target = target; - Target.Shadow = this; - } - - internal int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) - { - if (MicroComRuntime.TryGetTypeForGuid(*guid, out var type)) - return QueryInterface(type, ppv); - else if (*guid == MicroComRuntime.ManagedObjectInterfaceGuid) - { - ccw->RefCount++; - *ppv = ccw; - return 0; - } - else - return unchecked((int)0x80004002u); - } - - internal int QueryInterface(Type type, void** ppv) - { - if (!type.IsInstanceOfType(Target)) - return unchecked((int)0x80004002u); - - var rv = GetOrCreateNativePointer(type, ppv); - if (rv == 0) - AddRef((Ccw*)*ppv); - return rv; - } - - internal int GetOrCreateNativePointer(Type type, void** ppv) - { - if (!MicroComRuntime.GetVtableFor(type, out var vtable)) - return unchecked((int)0x80004002u); - lock (_lock) - { - - if (_shadows.TryGetValue(type, out var shadow)) - { - var targetCcw = (Ccw*)shadow; - AddRef(targetCcw); - *ppv = targetCcw; - return 0; - } - else - { - var intPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); - var targetCcw = (Ccw*)intPtr; - *targetCcw = default; - targetCcw->RefCount = 0; - targetCcw->VTable = vtable; - if (_handle == null) - _handle = GCHandle.Alloc(this); - targetCcw->GcShadowHandle = GCHandle.ToIntPtr(_handle.Value); - _shadows[type] = intPtr; - _backShadows[intPtr] = type; - *ppv = targetCcw; - - return 0; - } - } - } - - internal int AddRef(Ccw* ccw) - { - if (Interlocked.Increment(ref _refCount) == 1) - { - try - { - Target.OnReferencedFromNative(); - } - catch (Exception e) - { - MicroComRuntime.UnhandledException(Target, e); - } - } - - return Interlocked.Increment(ref ccw->RefCount); - } - - internal int Release(Ccw* ccw) - { - Interlocked.Decrement(ref _refCount); - var cnt = Interlocked.Decrement(ref ccw->RefCount); - if (cnt == 0) - return FreeCcw(ccw); - - return cnt; - } - - int FreeCcw(Ccw* ccw) - { - lock (_lock) - { - // Shadow got resurrected by a call to QueryInterface from another thread - if (ccw->RefCount != 0) - return ccw->RefCount; - - var intPtr = new IntPtr(ccw); - var type = _backShadows[intPtr]; - _backShadows.Remove(intPtr); - _shadows.Remove(type); - Marshal.FreeHGlobal(intPtr); - if (_shadows.Count == 0) - { - _handle?.Free(); - _handle = null; - try - { - Target.OnUnreferencedFromNative(); - } - catch(Exception e) - { - MicroComRuntime.UnhandledException(Target, e); - } - } - } - - return 0; - } - - /* - Needs to be called to support the following scenario: - 1) Object created - 2) Object passed to native code, shadow is created, CCW is created - 3) Native side has never called AddRef - - In that case the GC handle to the shadow object is still alive - */ - - public void Dispose() - { - lock (_lock) - { - List toRemove = null; - foreach (var kv in _backShadows) - { - var ccw = (Ccw*)kv.Key; - if (ccw->RefCount == 0) - { - toRemove ??= new List(); - toRemove.Add(kv.Key); - } - } - - if(toRemove != null) - foreach (var intPtr in toRemove) - FreeCcw((Ccw*)intPtr); - } - } - } - - [StructLayout(LayoutKind.Sequential)] - struct Ccw - { - public IntPtr VTable; - public IntPtr GcShadowHandle; - public volatile int RefCount; - public MicroComShadow GetShadow() => (MicroComShadow)GCHandle.FromIntPtr(GcShadowHandle).Target; - } -} diff --git a/src/Avalonia.MicroCom/MicroComVtblBase.cs b/src/Avalonia.MicroCom/MicroComVtblBase.cs deleted file mode 100644 index 7092f8131a..0000000000 --- a/src/Avalonia.MicroCom/MicroComVtblBase.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace Avalonia.MicroCom -{ - public unsafe class MicroComVtblBase - { - private List _methods = new List(); - [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] - private delegate int AddRefDelegate(Ccw* ccw); - - [UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)] - private delegate int QueryInterfaceDelegate(Ccw* ccw, Guid* guid, void** ppv); - - public static IntPtr Vtable { get; } = new MicroComVtblBase().CreateVTable(); - public MicroComVtblBase() - { - AddMethod((QueryInterfaceDelegate)QueryInterface); - AddMethod((AddRefDelegate)AddRef); - AddMethod((AddRefDelegate)Release); - } - - protected void AddMethod(void* f) - { - _methods.Add(new IntPtr(f)); - } - - protected void AddMethod(Delegate d) - { - GCHandle.Alloc(d); - _methods.Add(Marshal.GetFunctionPointerForDelegate(d)); - } - - protected unsafe IntPtr CreateVTable() - { - var ptr = (IntPtr*)Marshal.AllocHGlobal((IntPtr.Size + 1) * _methods.Count); - for (var c = 0; c < _methods.Count; c++) - ptr[c] = _methods[c]; - return new IntPtr(ptr); - } - - static int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) => ccw->GetShadow().QueryInterface(ccw, guid, ppv); - static int AddRef(Ccw* ccw) => ccw->GetShadow().AddRef(ccw); - static int Release(Ccw* ccw) => ccw->GetShadow().Release(ccw); - } -} diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 2001a2fcbc..4ceb1be340 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -6,7 +6,6 @@ true net6.0;netstandard2.0 true - Avalonia.MicroCom diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index b45fe5559b..532893884a 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -10,6 +10,7 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Composition; using JetBrains.Annotations; +using MicroCom.Runtime; namespace Avalonia.Native { diff --git a/src/Avalonia.Native/CallbackBase.cs b/src/Avalonia.Native/CallbackBase.cs index 56f9505cb4..2d875dbc0e 100644 --- a/src/Avalonia.Native/CallbackBase.cs +++ b/src/Avalonia.Native/CallbackBase.cs @@ -2,6 +2,7 @@ using System.Runtime.ExceptionServices; using Avalonia.MicroCom; using Avalonia.Platform; +using MicroCom.Runtime; namespace Avalonia.Native { diff --git a/src/Avalonia.Native/NativeControlHostImpl.cs b/src/Avalonia.Native/NativeControlHostImpl.cs index 2c9c1728d3..8a3488d95e 100644 --- a/src/Avalonia.Native/NativeControlHostImpl.cs +++ b/src/Avalonia.Native/NativeControlHostImpl.cs @@ -4,6 +4,7 @@ using Avalonia.MicroCom; using Avalonia.Native.Interop; using Avalonia.Platform; using Avalonia.VisualTree; +using MicroCom.Runtime; namespace Avalonia.Native { diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index 55d02b5d31..2f0bfd86a5 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -3,7 +3,6 @@ net6.0;netstandard2.0 true Avalonia.Win32 - Avalonia.MicroCom diff --git a/src/Windows/Avalonia.Win32/ClipboardImpl.cs b/src/Windows/Avalonia.Win32/ClipboardImpl.cs index 7cf8b14bed..7e058cb052 100644 --- a/src/Windows/Avalonia.Win32/ClipboardImpl.cs +++ b/src/Windows/Avalonia.Win32/ClipboardImpl.cs @@ -7,6 +7,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Threading; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32 { @@ -83,7 +84,7 @@ namespace Avalonia.Win32 while (true) { - var ptr = MicroCom.MicroComRuntime.GetNativeIntPtr(wrapper); + var ptr = wrapper.GetNativeIntPtr(); var hr = UnmanagedMethods.OleSetClipboard(ptr); if (hr == 0) @@ -107,7 +108,7 @@ namespace Avalonia.Win32 if (hr == 0) { - using var proxy = MicroCom.MicroComRuntime.CreateProxyFor(dataObject, true); + using var proxy = MicroComRuntime.CreateProxyFor(dataObject, true); using var wrapper = new OleDataObject(proxy); var formats = wrapper.GetDataFormats().ToArray(); return formats; @@ -131,7 +132,7 @@ namespace Avalonia.Win32 if (hr == 0) { - using var proxy = MicroCom.MicroComRuntime.CreateProxyFor(dataObject, true); + using var proxy = MicroComRuntime.CreateProxyFor(dataObject, true); using var wrapper = new OleDataObject(proxy); var rv = wrapper.Get(format); return rv; diff --git a/src/Windows/Avalonia.Win32/DragSource.cs b/src/Windows/Avalonia.Win32/DragSource.cs index 1159c5bfc9..53d4345c5e 100644 --- a/src/Windows/Avalonia.Win32/DragSource.cs +++ b/src/Windows/Avalonia.Win32/DragSource.cs @@ -3,6 +3,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Threading; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32 { @@ -19,8 +20,8 @@ namespace Avalonia.Win32 using var src = new OleDragSource(); var allowed = OleDropTarget.ConvertDropEffect(allowedEffects); - var objPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(dataObject); - var srcPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(src); + var objPtr = MicroComRuntime.GetNativeIntPtr(dataObject); + var srcPtr = MicroComRuntime.GetNativeIntPtr(src); UnmanagedMethods.DoDragDrop(objPtr, srcPtr, (int)allowed, out var finalEffect); diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index ea01d5cbdf..d1627aa13a 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices.ComTypes; using System.Text; using Avalonia.MicroCom; +using MicroCom.Runtime; using Avalonia.Win32.Win32Com; // ReSharper disable InconsistentNaming diff --git a/src/Windows/Avalonia.Win32/OleContext.cs b/src/Windows/Avalonia.Win32/OleContext.cs index c025d06fe7..e41423a334 100644 --- a/src/Windows/Avalonia.Win32/OleContext.cs +++ b/src/Windows/Avalonia.Win32/OleContext.cs @@ -5,6 +5,7 @@ using Avalonia.Platform; using Avalonia.Threading; using Avalonia.Win32.Interop; using Avalonia.Win32.Win32Com; +using MicroCom.Runtime; namespace Avalonia.Win32 { @@ -47,7 +48,7 @@ namespace Avalonia.Win32 return false; } - var trgPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(target); + var trgPtr = target.GetNativeIntPtr(); return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK; } diff --git a/src/Windows/Avalonia.Win32/OleDataObject.cs b/src/Windows/Avalonia.Win32/OleDataObject.cs index f7345b3ff7..90992d803f 100644 --- a/src/Windows/Avalonia.Win32/OleDataObject.cs +++ b/src/Windows/Avalonia.Win32/OleDataObject.cs @@ -10,7 +10,7 @@ using Avalonia.Input; using Avalonia.MicroCom; using Avalonia.Utilities; using Avalonia.Win32.Interop; - +using MicroCom.Runtime; using IDataObject = Avalonia.Input.IDataObject; namespace Avalonia.Win32 diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index 3d0d35228c..1c22fd025d 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -5,6 +5,7 @@ using Avalonia.Input.Raw; using Avalonia.MicroCom; using Avalonia.Platform; using Avalonia.Win32.Interop; +using MicroCom.Runtime; using DropEffect = Avalonia.Win32.Win32Com.DropEffect; namespace Avalonia.Win32 diff --git a/src/Windows/Avalonia.Win32/Win32StorageProvider.cs b/src/Windows/Avalonia.Win32/Win32StorageProvider.cs index bb1de56f2b..8cc0a380f9 100644 --- a/src/Windows/Avalonia.Win32/Win32StorageProvider.cs +++ b/src/Windows/Avalonia.Win32/Win32StorageProvider.cs @@ -12,6 +12,7 @@ using Avalonia.Platform.Storage; using Avalonia.Platform.Storage.FileIO; using Avalonia.Win32.Interop; using Avalonia.Win32.Win32Com; +using MicroCom.Runtime; namespace Avalonia.Win32 { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs index a09918a3a6..ef3de9fbe1 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs @@ -6,6 +6,7 @@ using Avalonia.MicroCom; using Avalonia.OpenGL; using Avalonia.OpenGL.Egl; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs index 9a6bd9572a..8a41c00add 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs @@ -12,6 +12,7 @@ using Avalonia.OpenGL.Angle; using Avalonia.OpenGL.Egl; using Avalonia.Rendering; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs index ea75a2f311..32f44842f8 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Runtime.InteropServices; using Avalonia.MicroCom; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs index 4ed882552b..fc04dcda26 100644 --- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs +++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs @@ -6,6 +6,7 @@ using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Surfaces; using Avalonia.Utilities; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT.Composition { diff --git a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs index 89cde01ff4..1794b022fe 100644 --- a/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs +++ b/src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using System.Threading; using Avalonia.MicroCom; using Avalonia.Win32.Interop; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT { diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs index d2ec957b8e..1fde57fe38 100644 --- a/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs +++ b/src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Avalonia.MicroCom; +using MicroCom.Runtime; namespace Avalonia.Win32.WinRT { From 89faa52240e1fb3b1f537d09bc5bcec050dfe983 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 19 Oct 2022 16:04:09 +0200 Subject: [PATCH 09/32] Use DragEventArgs for DragLeave event. This follows the WPF/UWP API and allows pointer information to be retrieved. --- src/Avalonia.Base/Input/DragDrop.cs | 2 +- src/Avalonia.Base/Input/DragDropDevice.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Base/Input/DragDrop.cs b/src/Avalonia.Base/Input/DragDrop.cs index 723d577964..fe75f678e1 100644 --- a/src/Avalonia.Base/Input/DragDrop.cs +++ b/src/Avalonia.Base/Input/DragDrop.cs @@ -13,7 +13,7 @@ namespace Avalonia.Input /// /// Event which is raised, when a drag-and-drop operation leaves the element. /// - public static readonly RoutedEvent DragLeaveEvent = RoutedEvent.Register("DragLeave", RoutingStrategies.Bubble, typeof(DragDrop)); + public static readonly RoutedEvent DragLeaveEvent = RoutedEvent.Register("DragLeave", RoutingStrategies.Bubble, typeof(DragDrop)); /// /// Event which is raised, when a drag-and-drop operation is updated while over the element. /// diff --git a/src/Avalonia.Base/Input/DragDropDevice.cs b/src/Avalonia.Base/Input/DragDropDevice.cs index 30a08eda17..3c91856dcd 100644 --- a/src/Avalonia.Base/Input/DragDropDevice.cs +++ b/src/Avalonia.Base/Input/DragDropDevice.cs @@ -54,7 +54,7 @@ namespace Avalonia.Input try { if (_lastTarget != null) - _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); + RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragLeaveEvent, effects, data, modifiers); return RaiseDragEvent(target, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } finally @@ -63,13 +63,13 @@ namespace Avalonia.Input } } - private void DragLeave(IInputElement inputRoot) + private void DragLeave(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, KeyModifiers modifiers) { if (_lastTarget == null) return; try { - _lastTarget.RaiseEvent(new RoutedEventArgs(DragDrop.DragLeaveEvent)); + RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragLeaveEvent, effects, data, modifiers); } finally { @@ -106,7 +106,7 @@ namespace Avalonia.Input e.Effects = DragOver(e.Root, e.Location, e.Data, e.Effects, e.KeyModifiers); break; case RawDragEventType.DragLeave: - DragLeave(e.Root); + DragLeave(e.Root, e.Location, e.Data, e.Effects, e.KeyModifiers); break; case RawDragEventType.Drop: e.Effects = Drop(e.Root, e.Location, e.Data, e.Effects, e.KeyModifiers); From a88fdd56b97ad1b2aa9907b03546b1da292dc8cf Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 19 Oct 2022 16:16:12 +0200 Subject: [PATCH 10/32] Adjust Microsoft.CodeAnalysis package version --- src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index b16ee84b4d..fe694b5730 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -19,7 +19,8 @@ - + + From 10b584d95c7dd903f18f706e1f64cdcaffbd18a2 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 19 Oct 2022 22:14:48 +0200 Subject: [PATCH 11/32] After the fix still causing issues, I figured the value must be >0xffff_ffff so not fitting. I changed to logic to handle that case too. --- src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index f28f4fd740..3bcc395abe 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -1877,7 +1877,10 @@ namespace Avalonia.Win32.Interop public static uint LGID(IntPtr HKL) { - return (uint)(HKL.ToInt64() & 0xffff); + unchecked + { + return (uint)((ulong)HKL & 0xffff); + } } public const int SORT_DEFAULT = 0; From d816726ef000545ea547bd1e24ea58be56bdb7c9 Mon Sep 17 00:00:00 2001 From: robloo Date: Wed, 19 Oct 2022 21:19:13 -0400 Subject: [PATCH 12/32] Rename Scale to Scaling and update more comments --- samples/ControlCatalog/Pages/ScreenPage.cs | 2 +- src/Avalonia.Controls/Platform/IScreenImpl.cs | 6 +++++ src/Avalonia.Controls/Platform/Screen.cs | 19 ++++++++++----- src/Avalonia.Controls/Screens.cs | 13 ++++++---- src/Avalonia.Native/ScreenImpl.cs | 4 ++-- src/Avalonia.Native/WindowImplBase.cs | 2 +- src/Avalonia.Native/avn.idl | 4 ++-- src/Avalonia.X11/X11Screens.cs | 24 +++++++++++-------- src/Avalonia.X11/X11Window.cs | 8 +++---- src/Windows/Avalonia.Win32/TrayIconImpl.cs | 8 +++---- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 +- 11 files changed, 56 insertions(+), 36 deletions(-) diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index 119bc09888..ab75e4a4e2 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -65,7 +65,7 @@ namespace ControlCatalog.Pages formattedText = CreateFormattedText($"Scaling: {screen.Scale * 100}%"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); - formattedText = CreateFormattedText($"Primary: {screen.IsPrimary}"); + formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 60)); formattedText = diff --git a/src/Avalonia.Controls/Platform/IScreenImpl.cs b/src/Avalonia.Controls/Platform/IScreenImpl.cs index fcae3b6493..e2a0b3e3f3 100644 --- a/src/Avalonia.Controls/Platform/IScreenImpl.cs +++ b/src/Avalonia.Controls/Platform/IScreenImpl.cs @@ -6,8 +6,14 @@ namespace Avalonia.Platform [Unstable] public interface IScreenImpl { + /// + /// Gets the total number of screens available on the device. + /// int ScreenCount { get; } + /// + /// Gets the list of all screens available on the device. + /// IReadOnlyList AllScreens { get; } Screen? ScreenFromWindow(IWindowBaseImpl window); diff --git a/src/Avalonia.Controls/Platform/Screen.cs b/src/Avalonia.Controls/Platform/Screen.cs index e5b8ca5555..4898c5f912 100644 --- a/src/Avalonia.Controls/Platform/Screen.cs +++ b/src/Avalonia.Controls/Platform/Screen.cs @@ -14,11 +14,11 @@ namespace Avalonia.Platform /// Multiply this value by 100 to get a percentage. /// Both X and Y scaling factors are assumed uniform. /// - public double Scale { get; } + public double Scaling { get; } - /// - [Obsolete("Use the Scale property instead.")] - public double PixelDensity => Scale; + /// + [Obsolete("Use the Scaling property instead.")] + public double PixelDensity => Scaling; /// /// Gets the overall pixel-size of the screen. @@ -46,9 +46,16 @@ namespace Avalonia.Platform [Obsolete("Use the IsPrimary property instead.")] public bool Primary => IsPrimary; - public Screen(double scale, PixelRect bounds, PixelRect workingArea, bool isPrimary) + /// + /// Initializes a new instance of the class. + /// + /// The scaling factor applied to the screen by the operating system. + /// The overall pixel-size of the screen. + /// The actual working-area pixel-size of the screen. + /// Whether the screen is the primary one. + public Screen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary) { - this.Scale = scale; + this.Scaling = scaling; this.Bounds = bounds; this.WorkingArea = workingArea; this.IsPrimary = isPrimary; diff --git a/src/Avalonia.Controls/Screens.cs b/src/Avalonia.Controls/Screens.cs index da37959402..dde6b71e6e 100644 --- a/src/Avalonia.Controls/Screens.cs +++ b/src/Avalonia.Controls/Screens.cs @@ -16,20 +16,23 @@ namespace Avalonia.Controls private readonly IScreenImpl _iScreenImpl; /// - /// Gets the total number of screens available on this device. + /// Gets the total number of screens available on the device. /// public int ScreenCount => _iScreenImpl?.ScreenCount ?? 0; /// - /// Gets the list of all screens available on this device. + /// Gets the list of all screens available on the device. /// public IReadOnlyList All => _iScreenImpl?.AllScreens ?? Array.Empty(); /// - /// Gets the primary screen on this device. + /// Gets the primary screen on the device. /// public Screen? Primary => All.FirstOrDefault(x => x.IsPrimary); + /// + /// Initializes a new instance of the class. + /// public Screens(IScreenImpl iScreenImpl) { _iScreenImpl = iScreenImpl; @@ -39,14 +42,14 @@ namespace Avalonia.Controls { return _iScreenImpl.ScreenFromRect(bounds); } - + public Screen? ScreenFromWindow(IWindowBaseImpl window) { return _iScreenImpl.ScreenFromWindow(window); } public Screen? ScreenFromPoint(PixelPoint point) - { + { return _iScreenImpl.ScreenFromPoint(point); } diff --git a/src/Avalonia.Native/ScreenImpl.cs b/src/Avalonia.Native/ScreenImpl.cs index 83db2e8a28..53bd12cde1 100644 --- a/src/Avalonia.Native/ScreenImpl.cs +++ b/src/Avalonia.Native/ScreenImpl.cs @@ -30,10 +30,10 @@ namespace Avalonia.Native var screen = _native.GetScreen(i); result[i] = new Screen( - screen.PixelDensity, + screen.Scaling, screen.Bounds.ToAvaloniaPixelRect(), screen.WorkingArea.ToAvaloniaPixelRect(), - screen.Primary.FromComBool()); + screen.IsPrimary.FromComBool()); } return result; diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 8bb2b0a713..381741cea9 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -92,7 +92,7 @@ namespace Avalonia.Native _savedScaling = RenderScaling; _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); - var monitor = Screen.AllScreens.OrderBy(x => x.Scale) + var monitor = Screen.AllScreens.OrderBy(x => x.Scaling) .FirstOrDefault(m => m.Bounds.Contains(Position)); Resize(new Size(monitor.WorkingArea.Width * 0.75d, monitor.WorkingArea.Height * 0.7d), PlatformResizeReason.Layout); diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl index a98d213887..b0bff07146 100644 --- a/src/Avalonia.Native/avn.idl +++ b/src/Avalonia.Native/avn.idl @@ -256,8 +256,8 @@ struct AvnScreen { AvnRect Bounds; AvnRect WorkingArea; - float PixelDensity; - bool Primary; + float Scaling; + bool IsPrimary; } enum AvnPixelFormat diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index a65f09ee63..ba6029b350 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -218,7 +218,7 @@ namespace Avalonia.X11 public int ScreenCount => _impl.Screens.Length; public IReadOnlyList AllScreens => - _impl.Screens.Select(s => new Screen(s.PixelDensity, s.Bounds, s.WorkingArea, s.IsPrimary)).ToArray(); + _impl.Screens.Select(s => new Screen(s.Scaling, s.Bounds, s.WorkingArea, s.IsPrimary)).ToArray(); } interface IX11Screens @@ -285,26 +285,30 @@ namespace Avalonia.X11 public string Name { get; set; } public PixelRect Bounds { get; set; } public Size? PhysicalSize { get; set; } - public double PixelDensity { get; set; } + public double Scaling { get; set; } public PixelRect WorkingArea { get; set; } - public X11Screen(PixelRect bounds, bool primary, - string name, Size? physicalSize, double? pixelDensity) + public X11Screen( + PixelRect bounds, + bool isPrimary, + string name, + Size? physicalSize, + double? scaling) { - IsPrimary = primary; + IsPrimary = isPrimary; Name = name; Bounds = bounds; - if (physicalSize == null && pixelDensity == null) + if (physicalSize == null && scaling == null) { - PixelDensity = 1; + Scaling = 1; } - else if (pixelDensity == null) + else if (scaling == null) { - PixelDensity = GuessPixelDensity(bounds, physicalSize.Value); + Scaling = GuessPixelDensity(bounds, physicalSize.Value); } else { - PixelDensity = pixelDensity.Value; + Scaling = scaling.Value; PhysicalSize = physicalSize; } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 75b741ac77..690ac0ebce 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -120,7 +120,7 @@ namespace Avalonia.X11 if (!_popup && Screen != null) { - var monitor = Screen.AllScreens.OrderBy(x => x.Scale) + var monitor = Screen.AllScreens.OrderBy(x => x.Scaling) .FirstOrDefault(m => m.Bounds.Contains(Position)); if (monitor != null) @@ -570,9 +570,9 @@ namespace Avalonia.X11 newScaling = _scalingOverride.Value; else { - var monitor = _platform.X11Screens.Screens.OrderBy(x => x.PixelDensity) + var monitor = _platform.X11Screens.Screens.OrderBy(x => x.Scaling) .FirstOrDefault(m => m.Bounds.Contains(Position)); - newScaling = monitor?.PixelDensity ?? RenderScaling; + newScaling = monitor?.Scaling ?? RenderScaling; } if (RenderScaling != newScaling) @@ -994,7 +994,7 @@ namespace Avalonia.X11 public IScreenImpl Screen => _platform.Screens; - public Size MaxAutoSizeHint => _platform.X11Screens.Screens.Select(s => s.Bounds.Size.ToSize(s.PixelDensity)) + public Size MaxAutoSizeHint => _platform.X11Screens.Screens.Select(s => s.Bounds.Size.ToSize(s.Scaling)) .OrderByDescending(x => x.Width + x.Height).FirstOrDefault(); diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs index 93bdfda652..8d565d7fef 100644 --- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs +++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs @@ -216,7 +216,7 @@ namespace Avalonia.Win32 { Anchor = PopupAnchor.TopLeft, Gravity = PopupGravity.BottomRight, - AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.Scale, new Size(1, 1)), + AnchorRectangle = new Rect(Position.ToPoint(1) / Screens.Primary.Scaling, new Size(1, 1)), Size = finalRect.Size, ConstraintAdjustment = PopupPositionerConstraintAdjustment.FlipX | PopupPositionerConstraintAdjustment.FlipY, }); @@ -244,16 +244,16 @@ namespace Avalonia.Win32 { var point = _hiddenWindow.Screens.Primary.Bounds.TopLeft; var size = _hiddenWindow.Screens.Primary.Bounds.Size; - return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.Scale, size.Height * _hiddenWindow.Screens.Primary.Scale); + return new Rect(point.X, point.Y, size.Width * _hiddenWindow.Screens.Primary.Scaling, size.Height * _hiddenWindow.Screens.Primary.Scaling); } } public void MoveAndResize(Point devicePoint, Size virtualSize) { - _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.Scale); + _moveResize(new PixelPoint((int)devicePoint.X, (int)devicePoint.Y), virtualSize, _hiddenWindow.Screens.Primary.Scaling); } - public double Scaling => _hiddenWindow.Screens.Primary.Scale; + public double Scaling => _hiddenWindow.Screens.Primary.Scaling; } } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index cd8515eaa6..5374614379 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -224,7 +224,7 @@ namespace Avalonia.Win32 } } - private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.Scale ?? 1; + private double PrimaryScreenRenderScaling => Screen.AllScreens.FirstOrDefault(screen => screen.IsPrimary)?.Scaling ?? 1; public double RenderScaling => _scaling; From 1cf220016f7bd63447b6447f31cd82256d0f548a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Oct 2022 13:31:16 +0100 Subject: [PATCH 13/32] focus the root container on page load. --- src/Web/Avalonia.Web/AvaloniaView.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs index 3a31679424..12d31258b5 100644 --- a/src/Web/Avalonia.Web/AvaloniaView.cs +++ b/src/Web/Avalonia.Web/AvaloniaView.cs @@ -136,6 +136,8 @@ namespace Avalonia.Web DomHelper.ObserveSize(host, null, OnSizeChanged); CanvasHelper.RequestAnimationFrame(_canvas, true); + + InputHelper.FocusElement(_containerElement); } private static RawPointerPoint ExtractRawPointerFromJSArgs(JSObject args) From 3f4034f0caf06dbdb36438666b391c0a8f62bdd6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Oct 2022 21:41:15 +0100 Subject: [PATCH 14/32] add github sponsors --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c5a719ce90..df070c35cf 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1,2 @@ +github: avaloniaui open_collective: avalonia From 5d8e4998c1208180395f8c2345c618c12e6bb817 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Oct 2022 22:05:39 +0100 Subject: [PATCH 15/32] prevent browser touch gestures happening outside of avalonia --- src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts index 2257d56a92..783710bb3e 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts @@ -11,6 +11,7 @@ export class AvaloniaDOM { host.tabIndex = 0; host.oncontextmenu = function () { return false; }; host.style.overflow = "hidden"; + host.style.touchAction = "none"; // Rendering target canvas const canvas = document.createElement("canvas"); From 668296b397210192d72c0107135f0cc76f1bc1c2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 20 Oct 2022 22:21:49 +0100 Subject: [PATCH 16/32] minify js --- src/Web/Avalonia.Web/webapp/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Avalonia.Web/webapp/build.js b/src/Web/Avalonia.Web/webapp/build.js index 6b6df4c300..81f863cac7 100644 --- a/src/Web/Avalonia.Web/webapp/build.js +++ b/src/Web/Avalonia.Web/webapp/build.js @@ -5,7 +5,7 @@ require("esbuild").build({ ], outdir: "../wwwroot", bundle: true, - minify: false, + minify: true, format: "esm", target: "es2016", platform: "browser", From 91d25f7416981eebebe769757d944627b2f7ab8c Mon Sep 17 00:00:00 2001 From: robloo Date: Thu, 20 Oct 2022 20:12:40 -0400 Subject: [PATCH 17/32] Fix missed property rename --- samples/ControlCatalog/Pages/ScreenPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs index ab75e4a4e2..ff62b834c4 100644 --- a/samples/ControlCatalog/Pages/ScreenPage.cs +++ b/samples/ControlCatalog/Pages/ScreenPage.cs @@ -62,7 +62,7 @@ namespace ControlCatalog.Pages CreateFormattedText($"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 20)); - formattedText = CreateFormattedText($"Scaling: {screen.Scale * 100}%"); + formattedText = CreateFormattedText($"Scaling: {screen.Scaling * 100}%"); context.DrawText(formattedText, boundsRect.Position.WithY(boundsRect.Size.Height + 40)); formattedText = CreateFormattedText($"IsPrimary: {screen.IsPrimary}"); From 9cbe262117e30a056177ebf80a87bc3c11d87d80 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 21 Oct 2022 22:05:43 +0100 Subject: [PATCH 18/32] fix copypasta --- src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts index 783710bb3e..668212964c 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts @@ -24,7 +24,7 @@ export class AvaloniaDOM { // Native controls host const nativeHost = document.createElement("div"); - canvas.id = `nativeHost${randomIdPart}`; + nativeHost.id = `nativeHost${randomIdPart}`; nativeHost.classList.add("avalonia-native-host"); nativeHost.style.left = "0px"; nativeHost.style.top = "0px"; @@ -34,7 +34,7 @@ export class AvaloniaDOM { // IME const inputElement = document.createElement("input"); - canvas.id = `input${randomIdPart}`; + inputElement.id = `inputElement${randomIdPart}`; inputElement.classList.add("avalonia-input-element"); inputElement.autocapitalize = "none"; inputElement.type = "text"; From 31cef0b54ffd22d3e565aa55d4e7e006e019e8d8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 21 Oct 2022 22:10:24 +0100 Subject: [PATCH 19/32] basic non-ime text input. --- src/Web/Avalonia.Web/AvaloniaView.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs index 12d31258b5..9d7a629836 100644 --- a/src/Web/Avalonia.Web/AvaloniaView.cs +++ b/src/Web/Avalonia.Web/AvaloniaView.cs @@ -254,7 +254,14 @@ namespace Avalonia.Web private bool OnKeyDown (string code, string key, int modifier) { - return _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, code, key, (RawInputModifiers)modifier); + var handled = _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, code, key, (RawInputModifiers)modifier); + + if (!handled) + { + handled = _topLevelImpl.RawTextEvent(key); + } + + return handled; } private bool OnKeyUp(string code, string key, int modifier) From e5b745694ac22c7129c28b12a29b216770a1dafd Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 21 Oct 2022 22:23:05 +0100 Subject: [PATCH 20/32] filter modifier text input events. --- src/Web/Avalonia.Web/AvaloniaView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs index 9d7a629836..296e411fa8 100644 --- a/src/Web/Avalonia.Web/AvaloniaView.cs +++ b/src/Web/Avalonia.Web/AvaloniaView.cs @@ -256,7 +256,7 @@ namespace Avalonia.Web { var handled = _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, code, key, (RawInputModifiers)modifier); - if (!handled) + if (!handled && key.Length == 1) { handled = _topLevelImpl.RawTextEvent(key); } From 1d19c37a37aa106c14002cbb88af701625f6fb34 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 22 Oct 2022 09:43:51 +0100 Subject: [PATCH 21/32] wasm prevent touch flashing android. --- src/Web/Avalonia.Web/AvaloniaView.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Web/Avalonia.Web/AvaloniaView.cs b/src/Web/Avalonia.Web/AvaloniaView.cs index 296e411fa8..098b06a0a2 100644 --- a/src/Web/Avalonia.Web/AvaloniaView.cs +++ b/src/Web/Avalonia.Web/AvaloniaView.cs @@ -77,8 +77,7 @@ namespace Avalonia.Web _topLevelImpl.SetCssCursor = (cursor) => { - InputHelper.SetCursor(_containerElement, cursor); // macOS - InputHelper.SetCursor(_canvas, cursor); // windows + InputHelper.SetCursor(_containerElement, cursor); }; _topLevel.Prepare(); From eb1c1971f1d92eb68d319cf4b3c032800f2d6600 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 22 Oct 2022 10:28:51 +0100 Subject: [PATCH 22/32] remove cursor style when we want normal cursor. --- src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts index 768414ccab..8198e09738 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts @@ -159,7 +159,12 @@ export class InputHelper { } public static setCursor(inputElement: HTMLInputElement, kind: string) { - inputElement.style.cursor = kind; + if(kind == "pointer"){ + inputElement.style.removeProperty("cursor"); + } + else { + inputElement.style.cursor = kind; + } } public static setBounds(inputElement: HTMLInputElement, x: number, y: number, caretWidth: number, caretHeight: number, caret: number) { From 116146e847ad8b3506de58ff6469a17b1ae729b9 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 22 Oct 2022 12:23:57 +0100 Subject: [PATCH 23/32] smooth resizing wasm. --- .../ControlCatalog.Web/ControlCatalog.Web.csproj | 5 ++--- samples/ControlCatalog.Web/Roots.xml | 1 + .../webapp/modules/avalonia/canvas.ts | 16 ++++++++-------- .../webapp/modules/avalonia/input.ts | 5 ++--- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/samples/ControlCatalog.Web/ControlCatalog.Web.csproj b/samples/ControlCatalog.Web/ControlCatalog.Web.csproj index 0ddec3444b..06a5466619 100644 --- a/samples/ControlCatalog.Web/ControlCatalog.Web.csproj +++ b/samples/ControlCatalog.Web/ControlCatalog.Web.csproj @@ -16,9 +16,8 @@ full true true - true - -O3 - -O3 + -O2 + -O2 diff --git a/samples/ControlCatalog.Web/Roots.xml b/samples/ControlCatalog.Web/Roots.xml index 3c13098159..b07fd86fa2 100644 --- a/samples/ControlCatalog.Web/Roots.xml +++ b/samples/ControlCatalog.Web/Roots.xml @@ -3,4 +3,5 @@ + diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts index 9ae9b3d2a8..8f3539b4f8 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts @@ -210,23 +210,23 @@ interface SizeWatcherInstance { export class SizeWatcher { static observer: ResizeObserver; static elements: Map; + private static lastMove: number; public static observe(element: HTMLElement, elementId: string | undefined, callback: (width: number, height: number) => void): void { if (!element || !callback) { return; } - SizeWatcher.init(); + callback(element.clientWidth, element.clientHeight); - const watcherElement = element as SizeWatcherElement; - watcherElement.SizeWatcher = { - callback + const handleResize = (args: UIEvent) => { + if (Date.now() - this.lastMove > 33) { + callback(element.clientWidth, element.clientHeight); + SizeWatcher.lastMove = Date.now(); + } }; - SizeWatcher.elements.set(elementId ?? element.id, element); - SizeWatcher.observer.observe(element); - - SizeWatcher.invoke(element); + window.addEventListener("resize", handleResize); } public static unobserve(elementId: string): void { diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts index 8198e09738..ddc1f54ae7 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts @@ -159,10 +159,9 @@ export class InputHelper { } public static setCursor(inputElement: HTMLInputElement, kind: string) { - if(kind == "pointer"){ + if (kind === "pointer") { inputElement.style.removeProperty("cursor"); - } - else { + } else { inputElement.style.cursor = kind; } } From 38717dafbbccc958089d532794819cb2517b019c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 22 Oct 2022 12:52:02 +0100 Subject: [PATCH 24/32] smooth resizing attempt 2. --- src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts index 8f3539b4f8..010c9cfacc 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts @@ -217,10 +217,12 @@ export class SizeWatcher { return; } + SizeWatcher.lastMove = Date.now(); + callback(element.clientWidth, element.clientHeight); const handleResize = (args: UIEvent) => { - if (Date.now() - this.lastMove > 33) { + if (Date.now() - SizeWatcher.lastMove > 40) { callback(element.clientWidth, element.clientHeight); SizeWatcher.lastMove = Date.now(); } From f5d3f9b2d332a5a68b316779493085ec4b064f80 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 22 Oct 2022 13:40:40 +0100 Subject: [PATCH 25/32] we dont handle gl makecurrent. --- .../webapp/modules/avalonia/canvas.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts index 010c9cfacc..62f62fe46f 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts @@ -106,12 +106,6 @@ export class Canvas { // add the draw to the next frame this.renderLoopRequest = window.requestAnimationFrame(() => { - if (this.glInfo) { - const GL = (globalThis as any).AvaloniaGL; - // make current - GL.makeContextCurrent(this.glInfo.context); - } - if (this.htmlCanvas.width !== this.newWidth) { this.htmlCanvas.width = this.newWidth ?? 0; } @@ -131,6 +125,11 @@ export class Canvas { } public setCanvasSize(width: number, height: number): void { + if (this.renderLoopRequest !== 0) { + window.cancelAnimationFrame(this.renderLoopRequest); + this.renderLoopRequest = 0; + } + this.newWidth = width; this.newHeight = height; @@ -142,11 +141,7 @@ export class Canvas { this.htmlCanvas.height = this.newHeight; } - if (this.glInfo) { - const GL = (globalThis as any).AvaloniaGL; - // make current - GL.makeContextCurrent(this.glInfo.context); - } + this.requestAnimationFrame(); } public static setCanvasSize(element: HTMLCanvasElement, width: number, height: number): void { From cd8358303e2d9cf4edde7ca9999ad82a4c72d474 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sat, 22 Oct 2022 14:26:03 +0100 Subject: [PATCH 26/32] 30fps resize. --- src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts index 62f62fe46f..47c501cbb7 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/canvas.ts @@ -217,7 +217,7 @@ export class SizeWatcher { callback(element.clientWidth, element.clientHeight); const handleResize = (args: UIEvent) => { - if (Date.now() - SizeWatcher.lastMove > 40) { + if (Date.now() - SizeWatcher.lastMove > 33) { callback(element.clientWidth, element.clientHeight); SizeWatcher.lastMove = Date.now(); } From 6f5bae821b47e4671da4456ad3acbed7b15bd6a2 Mon Sep 17 00:00:00 2001 From: robloo Date: Sat, 22 Oct 2022 11:38:48 -0400 Subject: [PATCH 27/32] Fix usage of updated Screen properties This fixes the macOS build --- native/Avalonia.Native/src/OSX/Screens.mm | 4 ++-- src/Windows/Avalonia.Win32/WinScreen.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/Screens.mm b/native/Avalonia.Native/src/OSX/Screens.mm index b9c75ed742..83ab1bfd01 100644 --- a/native/Avalonia.Native/src/OSX/Screens.mm +++ b/native/Avalonia.Native/src/OSX/Screens.mm @@ -41,9 +41,9 @@ public: ret->WorkingArea.X = [screen visibleFrame].origin.x; ret->WorkingArea.Y = ConvertPointY(ToAvnPoint([screen visibleFrame].origin)).Y - ret->WorkingArea.Height; - ret->PixelDensity = [screen backingScaleFactor]; + ret->Scaling = [screen backingScaleFactor]; - ret->Primary = index == 0; + ret->IsPrimary = index == 0; return S_OK; } diff --git a/src/Windows/Avalonia.Win32/WinScreen.cs b/src/Windows/Avalonia.Win32/WinScreen.cs index f103cc3b66..1038f41a17 100644 --- a/src/Windows/Avalonia.Win32/WinScreen.cs +++ b/src/Windows/Avalonia.Win32/WinScreen.cs @@ -7,7 +7,8 @@ namespace Avalonia.Win32 { private readonly IntPtr _hMonitor; - public WinScreen(double pixelDensity, PixelRect bounds, PixelRect workingArea, bool primary, IntPtr hMonitor) : base(pixelDensity, bounds, workingArea, primary) + public WinScreen(double scaling, PixelRect bounds, PixelRect workingArea, bool isPrimary, IntPtr hMonitor) + : base(scaling, bounds, workingArea, isPrimary) { _hMonitor = hMonitor; } From ab02289d9377cfaa38c72bcfae9cf31ce1f6478b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 23 Oct 2022 18:22:03 +0100 Subject: [PATCH 28/32] fix distortion on mobile chrome browser. --- src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts index 668212964c..385cdd4c41 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/dom.ts @@ -19,7 +19,6 @@ export class AvaloniaDOM { canvas.classList.add("avalonia-canvas"); canvas.style.backgroundColor = "#ccc"; canvas.style.width = "100%"; - canvas.style.height = "100%"; canvas.style.position = "absolute"; // Native controls host From 822d57cac6369d72aaee4d0a4a5ca0b5259cc8d7 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Mon, 24 Oct 2022 14:45:25 +0200 Subject: [PATCH 29/32] Use LangVersion preview for all projects --- build/SharedVersion.props | 2 +- .../Avalonia.Markup.Xaml.Loader.csproj | 1 - src/Markup/Avalonia.Markup/Avalonia.Markup.csproj | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 1b60bb4df9..5838519596 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -8,7 +8,7 @@ https://github.com/AvaloniaUI/Avalonia/ true CS1591 - latest + preview MIT Icon.png Avalonia is a cross-platform UI framework for .NET providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS and with experimental support for Android, iOS and WebAssembly. diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj b/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj index f9be3fd62a..1dc7ce5e99 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj @@ -5,7 +5,6 @@ true Avalonia.Markup.Xaml.Loader $(DefineConstants);XAMLX_INTERNAL - 11 diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj index 6b25cbbeab..6711c3dd3d 100644 --- a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj +++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj @@ -2,7 +2,6 @@ net6.0;netstandard2.0 Avalonia - 11 From fd46119d74fd7ef3779311bf0b91e26570288e54 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 24 Oct 2022 16:56:17 +0200 Subject: [PATCH 30/32] Add failing test for Viewbox DataContext binding. --- .../ViewboxTests.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs index 4ffd314857..629408bcba 100644 --- a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs @@ -1,4 +1,5 @@ using Avalonia.Controls.Shapes; +using Avalonia.Data; using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.UnitTests; @@ -207,6 +208,26 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(new Size(200, 200), target.DesiredSize); } + [Fact] + public void Child_DataContext_Binding_Works() + { + var data = new + { + Foo = "foo", + }; + + var target = new Viewbox() + { + DataContext = data, + Child = new Canvas + { + [!Canvas.DataContextProperty] = new Binding("Foo"), + }, + }; + + Assert.Equal("foo", target.Child.DataContext); + } + private bool TryGetScale(Viewbox viewbox, out Vector scale) { if (viewbox.InternalTransform is null) From 4740955ef4cdeac20367c2b3023967bac4e0585d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 24 Oct 2022 16:58:30 +0200 Subject: [PATCH 31/32] Set Viewbox logical parent. Fixes `DataContext` binding in `Viewbox.Child`. --- src/Avalonia.Controls/Viewbox.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index aabfd3ef18..07d877142e 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -42,6 +42,7 @@ namespace Avalonia.Controls // can be applied independently of the Viewbox and Child transforms. _containerVisual = new ViewboxContainer(); _containerVisual.RenderTransformOrigin = RelativePoint.TopLeft; + ((ISetLogicalParent)_containerVisual).SetParent(this); VisualChildren.Add(_containerVisual); } From 4c41c9c7dd2b6cbc2f7aa97df14a42e4ce288459 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 25 Oct 2022 12:11:10 +0100 Subject: [PATCH 32/32] Wasm optimal defaults (#9267) * introduce optimal defaults for wasm builds * dont include satelite assemblies. * always preventDefault mouse and pointer * fix argument order. * set initial heap size. * put properties in targets. * fix condition * restore props file * remove duplicate code. * allow people to override initial heap size... but not some critical properties, * add special ld flag. --- src/Web/Avalonia.Web/Avalonia.Web.props | 4 +-- src/Web/Avalonia.Web/Avalonia.Web.targets | 30 +++++++++++++++++++ src/Web/Avalonia.Web/Interop/CanvasHelper.cs | 2 +- .../webapp/modules/avalonia/input.ts | 20 +++++-------- 4 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/Web/Avalonia.Web/Avalonia.Web.props b/src/Web/Avalonia.Web/Avalonia.Web.props index 6c975cd284..668dd20789 100644 --- a/src/Web/Avalonia.Web/Avalonia.Web.props +++ b/src/Web/Avalonia.Web/Avalonia.Web.props @@ -1,5 +1,5 @@ - + - $(EmccExtraLDFlags) --js-library="$(MSBuildThisFileDirectory)\interop.js" + 16384000 diff --git a/src/Web/Avalonia.Web/Avalonia.Web.targets b/src/Web/Avalonia.Web/Avalonia.Web.targets index d1bec2aa93..b6a09b33ef 100644 --- a/src/Web/Avalonia.Web/Avalonia.Web.targets +++ b/src/Web/Avalonia.Web/Avalonia.Web.targets @@ -4,4 +4,34 @@ + + + True + $(EmccExtraLDFlags) --js-library="$(MSBuildThisFileDirectory)\interop.js" + $(EmccExtraLDFlags) -sERROR_ON_UNDEFINED_SYMBOLS=0 + true + + + + true + full + true + -Oz + -Oz + false + false + 0 + false + true + false + false + false + false + false + false + true + true + en + false + diff --git a/src/Web/Avalonia.Web/Interop/CanvasHelper.cs b/src/Web/Avalonia.Web/Interop/CanvasHelper.cs index efa94916fa..5bbe503bc1 100644 --- a/src/Web/Avalonia.Web/Interop/CanvasHelper.cs +++ b/src/Web/Avalonia.Web/Interop/CanvasHelper.cs @@ -33,7 +33,7 @@ internal static partial class CanvasHelper public static partial void RequestAnimationFrame(JSObject canvas, bool renderLoop); [JSImport("Canvas.setCanvasSize", AvaloniaModule.MainModuleName)] - public static partial void SetCanvasSize(JSObject canvas, int height, int width); + public static partial void SetCanvasSize(JSObject canvas, int width, int height); [JSImport("Canvas.initGL", AvaloniaModule.MainModuleName)] private static partial JSObject InitGL( diff --git a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts index ddc1f54ae7..faede82e0d 100644 --- a/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts +++ b/src/Web/Avalonia.Web/webapp/modules/avalonia/input.ts @@ -98,27 +98,23 @@ export class InputHelper { wheelCallback: (args: WheelEvent) => boolean ) { const pointerMoveHandler = (args: PointerEvent) => { - if (pointerMoveCallback(args)) { - args.preventDefault(); - } + pointerMoveCallback(args); + args.preventDefault(); }; const pointerDownHandler = (args: PointerEvent) => { - if (pointerDownCallback(args)) { - args.preventDefault(); - } + pointerDownCallback(args); + args.preventDefault(); }; const pointerUpHandler = (args: PointerEvent) => { - if (pointerUpCallback(args)) { - args.preventDefault(); - } + pointerUpCallback(args); + args.preventDefault(); }; const wheelHandler = (args: WheelEvent) => { - if (wheelCallback(args)) { - args.preventDefault(); - } + wheelCallback(args); + args.preventDefault(); }; element.addEventListener("pointermove", pointerMoveHandler);