From a0e8dca6e97bc55f8b68df2eef020457849cf939 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Sep 2018 22:47:03 +0200 Subject: [PATCH 001/197] Use PixelSize for device-dependent sizes. --- src/Avalonia.Controls/Image.cs | 5 +- src/Avalonia.Controls/Remote/RemoteWidget.cs | 8 +- .../Remote/Server/RemoteServerTopLevelImpl.cs | 2 +- src/Avalonia.Visuals/Avalonia.Visuals.csproj | 1 + src/Avalonia.Visuals/Media/Imaging/Bitmap.cs | 31 ++-- src/Avalonia.Visuals/Media/Imaging/IBitmap.cs | 21 ++- .../Media/Imaging/RenderTargetBitmap.cs | 29 +-- .../Media/Imaging/WriteableBitmap.cs | 11 +- src/Avalonia.Visuals/Media/PixelSize.cs | 174 ++++++++++++++++++ src/Avalonia.Visuals/Platform/IBitmapImpl.cs | 8 +- .../Platform/ILockedFramebuffer.cs | 9 +- .../Platform/IPlatformRenderInterface.cs | 32 ++-- .../Platform/LockedFramebuffer.cs | 10 +- .../Rendering/DeferredRenderer.cs | 8 +- .../Avalonia.Gtk3/ImageSurfaceFramebuffer.cs | 10 +- src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs | 18 +- .../LockedFramebuffer.cs | 9 +- .../Avalonia.MonoMac/EmulatedFramebuffer.cs | 12 +- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 6 +- .../Avalonia.Skia/FramebufferRenderTarget.cs | 2 +- src/Skia/Avalonia.Skia/ImmutableBitmap.cs | 27 ++- .../Avalonia.Skia/PlatformRenderInterface.cs | 30 ++- src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs | 18 +- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 28 ++- .../Avalonia.Direct2D1/Direct2D1Platform.cs | 20 +- .../FramebufferShimRenderTarget.cs | 4 +- .../Media/DrawingContextImpl.cs | 8 +- .../Media/ImageBrushImpl.cs | 4 +- .../Media/Imaging/BitmapImpl.cs | 4 +- .../Media/Imaging/D2DBitmapImpl.cs | 4 +- .../Imaging/D2DRenderTargetBitmapImpl.cs | 3 - .../Media/Imaging/WicBitmapImpl.cs | 38 ++-- .../Imaging/WicRenderTargetBitmapImpl.cs | 12 +- .../Media/Imaging/WriteableWicBitmapImpl.cs | 7 +- .../Avalonia.Direct2D1/PrimitiveExtensions.cs | 4 + .../Wpf/WritableBitmapSurface.cs | 3 +- .../Avalonia.Win32/FramebufferManager.cs | 4 +- .../Avalonia.Win32/WindowFramebuffer.cs | 28 ++- .../Avalonia.Controls.UnitTests/ImageTests.cs | 8 +- .../Avalonia.RenderTests/Media/BitmapTests.cs | 21 +-- tests/Avalonia.RenderTests/TestBase.cs | 11 +- .../MockPlatformRenderInterface.cs | 18 +- .../VisualTree/MockRenderInterface.cs | 6 +- 43 files changed, 436 insertions(+), 280 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/PixelSize.cs diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index 802b700a07..7fa68147d7 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -57,7 +57,7 @@ namespace Avalonia.Controls if (source != null) { Rect viewPort = new Rect(Bounds.Size); - Size sourceSize = new Size(source.PixelWidth, source.PixelHeight); + Size sourceSize = new Size(source.PixelSize.Width, source.PixelSize.Height); Vector scale = Stretch.CalculateScaling(Bounds.Size, sourceSize); Size scaledSize = sourceSize * scale; Rect destRect = viewPort @@ -83,8 +83,7 @@ namespace Avalonia.Controls if (source != null) { - Size sourceSize = new Size(source.PixelWidth, source.PixelHeight); - + Size sourceSize = new Size(source.PixelSize.Width, source.PixelSize.Height); if (double.IsInfinity(availableSize.Width) || double.IsInfinity(availableSize.Height)) { return sourceSize; diff --git a/src/Avalonia.Controls/Remote/RemoteWidget.cs b/src/Avalonia.Controls/Remote/RemoteWidget.cs index 2d4f2e6b52..5a5ae97f4a 100644 --- a/src/Avalonia.Controls/Remote/RemoteWidget.cs +++ b/src/Avalonia.Controls/Remote/RemoteWidget.cs @@ -59,9 +59,9 @@ namespace Avalonia.Controls.Remote if (_lastFrame != null) { var fmt = (PixelFormat) _lastFrame.Format; - if (_bitmap == null || _bitmap.PixelWidth != _lastFrame.Width || - _bitmap.PixelHeight != _lastFrame.Height) - _bitmap = new WriteableBitmap(_lastFrame.Width, _lastFrame.Height, fmt); + if (_bitmap == null || _bitmap.PixelSize.Width != _lastFrame.Width || + _bitmap.PixelSize.Height != _lastFrame.Height) + _bitmap = new WriteableBitmap(new PixelSize(_lastFrame.Width, _lastFrame.Height), new Vector(96, 96), fmt); using (var l = _bitmap.Lock()) { var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width; @@ -69,7 +69,7 @@ namespace Avalonia.Controls.Remote Marshal.Copy(_lastFrame.Data, y * _lastFrame.Stride, new IntPtr(l.Address.ToInt64() + l.RowBytes * y), lineLen); } - context.DrawImage(_bitmap, 1, new Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight), + context.DrawImage(_bitmap, 1, new Rect(0, 0, _bitmap.PixelSize.Width, _bitmap.PixelSize.Height), new Rect(Bounds.Size)); } base.Render(context); diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index b302f2f5ec..551428244a 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -108,7 +108,7 @@ namespace Avalonia.Controls.Remote.Server var handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { - _framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), width, height, width * bpp, _dpi, (PixelFormat)fmt, + _framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), new PixelSize(width, height), width * bpp, _dpi, (PixelFormat)fmt, null); Paint?.Invoke(new Rect(0, 0, width, height)); } diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index c34752a3ef..c88001cc0a 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -1,6 +1,7 @@  netstandard2.0 + Avalonia diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs index cb98ed9a9c..0ad826f5a9 100644 --- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs @@ -56,30 +56,29 @@ namespace Avalonia.Media.Imaging { PlatformImpl.Dispose(); } - + /// /// Initializes a new instance of the class. /// - /// Pixel format - /// Pointer to source bytes - /// Bitmap width - /// Bitmap height - /// Bytes per row - public Bitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + /// The pixel format. + /// The pointer to the source bytes. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The number of bytes per row. + public Bitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) { PlatformImpl = RefCountable.Create(AvaloniaLocator.Current.GetService() - .LoadBitmap(format, data, width, height, stride)); + .LoadBitmap(format, data, size, dpi, stride)); } - /// - /// Gets the width of the bitmap, in pixels. - /// - public int PixelWidth => PlatformImpl.Item.PixelWidth; + /// + public Vector Dpi => PlatformImpl.Item.Dpi; - /// - /// Gets the height of the bitmap, in pixels. - /// - public int PixelHeight => PlatformImpl.Item.PixelHeight; + /// + public Size Size => PlatformImpl.Item.PixelSize.ToSize(Dpi); + + /// + public PixelSize PixelSize => PlatformImpl.Item.PixelSize; /// /// Gets the platform-specific bitmap implementation. diff --git a/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs index 465173059e..90b13088e1 100644 --- a/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/IBitmap.cs @@ -14,20 +14,33 @@ namespace Avalonia.Media.Imaging public interface IBitmap : IDisposable { /// - /// Gets the width of the bitmap, in pixels. + /// Gets the dots per inch (DPI) of the image. /// - int PixelWidth { get; } + /// + /// Note that Skia does not currently support reading the DPI of an image so this value + /// will always be 96dpi on Skia. + /// + Vector Dpi { get; } /// - /// Gets the height of the bitmap, in pixels. + /// Gets the size of the bitmap, in device pixels. /// - int PixelHeight { get; } + PixelSize PixelSize { get; } /// /// Gets the platform-specific bitmap implementation. /// IRef PlatformImpl { get; } + /// + /// Gets the size of the image, in device independent pixels. + /// + /// + /// Note that Skia does not currently support reading the DPI of an image so this value + /// will equal on Skia. + /// + Size Size { get; } + /// /// Saves the bitmap to a file. /// diff --git a/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs index db2259dde3..d0b85ef14e 100644 --- a/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/RenderTargetBitmap.cs @@ -17,12 +17,19 @@ namespace Avalonia.Media.Imaging /// /// Initializes a new instance of the class. /// - /// The width of the bitmap in pixels. - /// The height of the bitmap in pixels. - /// The horizontal DPI of the bitmap. - /// The vertical DPI of the bitmap. - public RenderTargetBitmap(int pixelWidth, int pixelHeight, double dpiX = 96, double dpiY = 96) - : this(RefCountable.Create(CreateImpl(pixelWidth, pixelHeight, dpiX, dpiY))) + /// The size of the bitmap. + public RenderTargetBitmap(PixelSize pixelSize) + : this(pixelSize, new Vector(96, 96)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + public RenderTargetBitmap(PixelSize pixelSize, Vector dpi) + : this(RefCountable.Create(CreateImpl(pixelSize, dpi))) { } @@ -45,15 +52,13 @@ namespace Avalonia.Media.Imaging /// /// Creates a platform-specific implementation for a . /// - /// The width of the bitmap. - /// The height of the bitmap. - /// The horizontal DPI of the bitmap. - /// The vertical DPI of the bitmap. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. /// The platform-specific implementation. - private static IRenderTargetBitmapImpl CreateImpl(int width, int height, double dpiX, double dpiY) + private static IRenderTargetBitmapImpl CreateImpl(PixelSize size, Vector dpi) { IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); - return factory.CreateRenderTargetBitmap(width, height, dpiX, dpiY); + return factory.CreateRenderTargetBitmap(size, dpi); } /// diff --git a/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs index 529c2efa42..88c0799cb9 100644 --- a/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs @@ -7,8 +7,15 @@ namespace Avalonia.Media.Imaging /// public class WriteableBitmap : Bitmap { - public WriteableBitmap(int width, int height, PixelFormat? format = null) - : base(AvaloniaLocator.Current.GetService().CreateWriteableBitmap(width, height, format)) + /// + /// Initializes a new instance of the class. + /// + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The pixel format (optional). + /// An . + public WriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) + : base(AvaloniaLocator.Current.GetService().CreateWriteableBitmap(size, dpi, format)) { } diff --git a/src/Avalonia.Visuals/Media/PixelSize.cs b/src/Avalonia.Visuals/Media/PixelSize.cs new file mode 100644 index 0000000000..3d0ae0b351 --- /dev/null +++ b/src/Avalonia.Visuals/Media/PixelSize.cs @@ -0,0 +1,174 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using Avalonia.Utilities; + +namespace Avalonia +{ + /// + /// Represents a size in device pixels. + /// + public readonly struct PixelSize + { + /// + /// A size representing zero + /// + public static readonly PixelSize Empty = new PixelSize(0, 0); + + /// + /// Initializes a new instance of the structure. + /// + /// The width. + /// The height. + public PixelSize(int width, int height) + { + Width = width; + Height = height; + } + + /// + /// Gets the aspect ratio of the size. + /// + public double AspectRatio => (double)Width / Height; + + /// + /// Gets the width. + /// + public int Width { get; } + + /// + /// Gets the height. + /// + public int Height { get; } + + /// + /// Checks for equality between two s. + /// + /// The first size. + /// The second size. + /// True if the sizes are equal; otherwise false. + public static bool operator ==(PixelSize left, PixelSize right) + { + return left.Width == right.Width && left.Height == right.Height; + } + + /// + /// Checks for inequality between two s. + /// + /// The first size. + /// The second size. + /// True if the sizes are unequal; otherwise false. + public static bool operator !=(PixelSize left, PixelSize right) + { + return !(left == right); + } + + /// + /// Parses a string. + /// + /// The string. + /// The . + public static PixelSize Parse(string s) + { + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Size")) + { + return new PixelSize( + tokenizer.ReadInt32(), + tokenizer.ReadInt32()); + } + } + + /// + /// Checks for equality between a size and an object. + /// + /// The object. + /// + /// True if is a size that equals the current size. + /// + public override bool Equals(object obj) + { + if (obj is PixelSize other) + { + return this == other; + } + + return false; + } + + /// + /// Returns a hash code for a . + /// + /// The hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + Width.GetHashCode(); + hash = (hash * 23) + Height.GetHashCode(); + return hash; + } + } + + /// + /// Returns a new with the same height and the specified width. + /// + /// The width. + /// The new . + public PixelSize WithWidth(int width) => new PixelSize(width, Height); + + /// + /// Returns a new with the same width and the specified height. + /// + /// The height. + /// The new . + public PixelSize WithHeight(int height) => new PixelSize(Width, height); + + /// + /// Converts the to a device-independent using the + /// specified dots per inch (DPI). + /// + /// The dots per inch. + /// The device-independent size. + public Size ToSize(double dpi) => new Size(Width / (dpi / 96), Height / (dpi / 96)); + + /// + /// Converts the to a device-independent using the + /// specified dots per inch (DPI). + /// + /// The dots per inch. + /// The device-independent size. + public Size ToSize(Vector dpi) => new Size(Width / (dpi.X / 96), Height / (dpi.Y / 96)); + + /// + /// Converts a to device pixels using the specified dots per inch (DPI). + /// + /// The size. + /// The dots per inch. + /// The device-independent size. + public static PixelSize FromSize(Size size, double dpi) => new PixelSize( + (int)(size.Width * (dpi / 96)), + (int)(size.Height * (dpi / 96))); + + /// + /// Converts a to device pixels using the specified dots per inch (DPI). + /// + /// The size. + /// The dots per inch. + /// The device-independent size. + public static PixelSize FromSize(Size size, Vector dpi) => new PixelSize( + (int)(size.Width * (dpi.X / 96)), + (int)(size.Height * (dpi.Y / 96))); + + /// + /// Returns the string representation of the size. + /// + /// The string representation of the size. + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", Width, Height); + } + } +} diff --git a/src/Avalonia.Visuals/Platform/IBitmapImpl.cs b/src/Avalonia.Visuals/Platform/IBitmapImpl.cs index d60838452e..f9608f9ea0 100644 --- a/src/Avalonia.Visuals/Platform/IBitmapImpl.cs +++ b/src/Avalonia.Visuals/Platform/IBitmapImpl.cs @@ -12,14 +12,14 @@ namespace Avalonia.Platform public interface IBitmapImpl : IDisposable { /// - /// Gets the width of the bitmap, in pixels. + /// Gets the dots per inch (DPI) of the image. /// - int PixelWidth { get; } + Vector Dpi { get; } /// - /// Gets the height of the bitmap, in pixels. + /// Gets the size of the bitmap, in device pixels. /// - int PixelHeight { get; } + PixelSize PixelSize { get; } /// /// Saves the bitmap to a file. diff --git a/src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs b/src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs index 45ca1a5a99..2f631142d2 100644 --- a/src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs +++ b/src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs @@ -10,14 +10,9 @@ namespace Avalonia.Platform IntPtr Address { get; } /// - /// Framebuffer width + /// Gets the framebuffer size in device pixels. /// - int Width { get; } - - /// - /// Framebuffer height - /// - int Height { get; } + PixelSize Size{ get; } /// /// Number of bytes per row diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index cc17efd2bb..aacdef0538 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -49,25 +49,19 @@ namespace Avalonia.Platform /// /// Creates a render target bitmap implementation. /// - /// The width of the bitmap. - /// The height of the bitmap. - /// The horizontal DPI of the bitmap. - /// The vertical DPI of the bitmap. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. /// An . - IRenderTargetBitmapImpl CreateRenderTargetBitmap( - int width, - int height, - double dpiX, - double dpiY); + IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi); /// /// Creates a writeable bitmap implementation. /// - /// The width of the bitmap. - /// The height of the bitmap. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. /// Pixel format (optional). /// An . - IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = null); + IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null); /// /// Loads a bitmap implementation from a file.. @@ -84,14 +78,14 @@ namespace Avalonia.Platform IBitmapImpl LoadBitmap(Stream stream); /// - /// Loads a bitmap implementation from a pixels in memory.. + /// Loads a bitmap implementation from a pixels in memory. /// - /// Pixel format - /// Pointer to source bytes - /// Bitmap width - /// Bitmap height - /// Bytes per row + /// The pixel format. + /// The pointer to source bytes. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The number of bytes per row. /// An . - IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride); + IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride); } } diff --git a/src/Avalonia.Visuals/Platform/LockedFramebuffer.cs b/src/Avalonia.Visuals/Platform/LockedFramebuffer.cs index c03b714956..c5b3c048b1 100644 --- a/src/Avalonia.Visuals/Platform/LockedFramebuffer.cs +++ b/src/Avalonia.Visuals/Platform/LockedFramebuffer.cs @@ -6,21 +6,19 @@ namespace Avalonia.Platform { private readonly Action _onDispose; - public LockedFramebuffer(IntPtr address, int width, int height, int rowBytes, Vector dpi, PixelFormat format, + public LockedFramebuffer(IntPtr address, PixelSize size, int rowBytes, Vector dpi, PixelFormat format, Action onDispose) { _onDispose = onDispose; Address = address; - Width = width; - Height = height; + Size = Size; RowBytes = rowBytes; Dpi = dpi; Format = format; } public IntPtr Address { get; } - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } public Vector Dpi { get; } public PixelFormat Format { get; } @@ -30,4 +28,4 @@ namespace Avalonia.Platform _onDispose?.Invoke(); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index dc1d2933d0..52172f654e 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -344,7 +344,7 @@ namespace Avalonia.Rendering foreach (var layer in scene.Layers) { var bitmap = Layers[layer.LayerRoot].Bitmap; - var sourceRect = new Rect(0, 0, bitmap.Item.PixelWidth, bitmap.Item.PixelHeight); + var sourceRect = new Rect(0, 0, bitmap.Item.PixelSize.Width, bitmap.Item.PixelSize.Height); if (layer.GeometryClip != null) { @@ -368,7 +368,7 @@ namespace Avalonia.Rendering if (_overlay != null) { - var sourceRect = new Rect(0, 0, _overlay.Item.PixelWidth, _overlay.Item.PixelHeight); + var sourceRect = new Rect(0, 0, _overlay.Item.PixelSize.Width, _overlay.Item.PixelSize.Height); context.DrawImage(_overlay, 0.5, sourceRect, clientRect); } @@ -453,8 +453,8 @@ namespace Avalonia.Rendering var pixelSize = size * scaling; if (_overlay == null || - _overlay.Item.PixelWidth != pixelSize.Width || - _overlay.Item.PixelHeight != pixelSize.Height) + _overlay.Item.PixelSize.Width != pixelSize.Width || + _overlay.Item.PixelSize.Height != pixelSize.Height) { _overlay?.Dispose(); _overlay = RefCountable.Create(parentContext.CreateLayer(size)); diff --git a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs index cd0074c287..44d887241c 100644 --- a/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs +++ b/src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs @@ -22,8 +22,7 @@ namespace Avalonia.Gtk3 height *= _factor; _surface = new ManagedCairoSurface(width, height); - Width = width; - Height = height; + Size = new PixelSize(width, height); Address = _surface.Buffer; RowBytes = _surface.Stride; Native.CairoSurfaceFlush(_surface.Surface); @@ -115,18 +114,17 @@ namespace Avalonia.Gtk3 if (_impl.CurrentCairoContext != IntPtr.Zero) Draw(_impl.CurrentCairoContext, _surface.Surface, _factor); else - DrawToWidget(_widget, _surface.Surface, Width, Height, _factor); + DrawToWidget(_widget, _surface.Surface, Size.Width, Size.Height, _factor); _surface.Dispose(); } else - _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, _factor, Width, Height)); + _impl.SetNextRenderOperation(new RenderOp(_widget, _surface, _factor, Size.Width, Size.Height)); _surface = null; } } public IntPtr Address { get; } - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } diff --git a/src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs b/src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs index dde29f85c2..c84d7c7541 100644 --- a/src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs +++ b/src/Gtk/Avalonia.Gtk3/X11Framebuffer.cs @@ -13,12 +13,11 @@ namespace Avalonia.Gtk3 { _display = display; _xid = xid; - Width = width*factor; - Height = height*factor; - RowBytes = Width * 4; + Size = new PixelSize(width * factor, height * factor); + RowBytes = Size.Width * 4; Dpi = new Vector(96, 96) * factor; Format = PixelFormat.Bgra8888; - _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * Height); + _blob = AvaloniaLocator.Current.GetService().AllocBlob(RowBytes * Size.Height); Address = _blob.Address; } @@ -26,8 +25,8 @@ namespace Avalonia.Gtk3 { var image = new X11.XImage(); int bitsPerPixel = 32; - image.width = Width; - image.height = Height; + image.width = Size.Width; + image.height = Size.Height; image.format = 2; //ZPixmap; image.data = Address; image.byte_order = 0;// LSBFirst; @@ -35,12 +34,12 @@ namespace Avalonia.Gtk3 image.bitmap_bit_order = 0;// LSBFirst; image.bitmap_pad = bitsPerPixel; image.depth = 24; - image.bytes_per_line = RowBytes - Width * 4; + image.bytes_per_line = RowBytes - Size.Width * 4; image.bits_per_pixel = bitsPerPixel; X11.XLockDisplay(_display); X11.XInitImage(ref image); var gc = X11.XCreateGC(_display, _xid, 0, IntPtr.Zero); - X11.XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint) Width, (uint) Height); + X11.XPutImage(_display, _xid, gc, ref image, 0, 0, 0, 0, (uint)Size.Width, (uint)Size.Height); X11.XFreeGC(_display, gc); X11.XSync(_display, true); X11.XUnlockDisplay(_display); @@ -48,8 +47,7 @@ namespace Avalonia.Gtk3 } public IntPtr Address { get; } - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } public Vector Dpi { get; } public PixelFormat Format { get; } diff --git a/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs b/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs index 795d9648ea..ed59166eb8 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/LockedFramebuffer.cs @@ -19,7 +19,7 @@ namespace Avalonia.LinuxFramebuffer _address = address; Dpi = dpi; //Use double buffering to avoid flicker - Address = Marshal.AllocHGlobal(RowBytes * Height); + Address = Marshal.AllocHGlobal(RowBytes * Size.Height); } @@ -31,17 +31,16 @@ namespace Avalonia.LinuxFramebuffer public void Dispose() { VSync(); - NativeUnsafeMethods.memcpy(_address, Address, new IntPtr(RowBytes * Height)); + NativeUnsafeMethods.memcpy(_address, Address, new IntPtr(RowBytes * Size.Height)); Marshal.FreeHGlobal(Address); Address = IntPtr.Zero; } public IntPtr Address { get; private set; } - public int Width => (int)_varInfo.xres; - public int Height => (int) _varInfo.yres; + public PixelSize Size => new PixelSize((int)_varInfo.xres, (int) _varInfo.yres); public int RowBytes => (int) _fixedInfo.line_length; public Vector Dpi { get; } public PixelFormat Format => _varInfo.blue.offset == 16 ? PixelFormat.Rgba8888 : PixelFormat.Bgra8888; } -} \ No newline at end of file +} diff --git a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs b/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs index 4da67ae1dd..8838c43201 100644 --- a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs +++ b/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs @@ -24,12 +24,11 @@ namespace Avalonia.MonoMac _isDeferred = !Dispatcher.UIThread.CheckAccess(); _logicalSize = _view.LogicalSize; var pixelSize = _view.PixelSize; - Width = (int)pixelSize.Width; - Height = (int)pixelSize.Height; - RowBytes = Width * 4; + Size = new PixelSize((int)pixelSize.Width, (int)pixelSize.Height); + RowBytes = Size.Width * 4; Dpi = new Vector(96 * pixelSize.Width / _logicalSize.Width, 96 * pixelSize.Height / _logicalSize.Height); Format = PixelFormat.Rgba8888; - var size = Height * RowBytes; + var size = Size.Height * RowBytes; _blob = AvaloniaLocator.Current.GetService().AllocBlob(size); memset(Address, 0, new IntPtr(size)); } @@ -43,7 +42,7 @@ namespace Avalonia.MonoMac try { using (var colorSpace = CGColorSpace.CreateDeviceRGB()) - using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, + using (var bContext = new CGBitmapContext(Address, Size.Width, Size.Height, 8, Size.Width * 4, colorSpace, (CGImageAlphaInfo)nfo)) image = bContext.ToImage(); lock (_view.SyncRoot) @@ -79,8 +78,7 @@ namespace Avalonia.MonoMac } public IntPtr Address => _blob.Address; - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } public Vector Dpi { get; } public PixelFormat Format { get; } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 685987ae80..c8fb8f4033 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -135,7 +135,7 @@ namespace Avalonia.Skia public void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { PushOpacityMask(opacityMask, opacityMaskRect); - DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect, BitmapInterpolationMode.Default); + DrawImage(source, 1, new Rect(0, 0, source.Item.PixelSize.Width, source.Item.PixelSize.Height), destRect, BitmapInterpolationMode.Default); PopOpacityMask(); } @@ -384,7 +384,7 @@ namespace Avalonia.Skia private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) { var calc = new TileBrushCalculator(tileBrush, - new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); + new Size(tileBrushImage.PixelSize.Width, tileBrushImage.PixelSize.Height), targetSize); var intermediate = CreateRenderTarget( (int)calc.IntermediateSize.Width, @@ -394,7 +394,7 @@ namespace Avalonia.Skia using (var context = intermediate.CreateDrawingContext(null)) { - var rect = new Rect(0, 0, tileBrushImage.PixelWidth, tileBrushImage.PixelHeight); + var rect = new Rect(0, 0, tileBrushImage.PixelSize.Width, tileBrushImage.PixelSize.Height); context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 829b9097c9..b2c936d6ad 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -41,7 +41,7 @@ namespace Avalonia.Skia public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) { var framebuffer = _platformSurface.Lock(); - var framebufferImageInfo = new SKImageInfo(framebuffer.Width, framebuffer.Height, + var framebufferImageInfo = new SKImageInfo(framebuffer.Size.Width, framebuffer.Size.Height, framebuffer.Format.ToSkColorType(), SKAlphaType.Premul); CreateSurface(framebufferImageInfo, framebuffer); diff --git a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs index 332b8547bf..ee3a3b1a32 100644 --- a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs +++ b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs @@ -31,22 +31,24 @@ namespace Avalonia.Skia throw new ArgumentException("Unable to load bitmap from provided data"); } - PixelWidth = _image.Width; - PixelHeight = _image.Height; + PixelSize = new PixelSize(_image.Width, _image.Height); + + // TODO: Skia doesn't have an API for DPI. + Dpi = new Vector(96, 96); } } /// /// Create immutable bitmap from given pixel data copy. /// - /// Width of data pixels. - /// Height of data pixels. + /// Size of the bitmap. + /// DPI of the bitmap. /// Stride of data pixels. /// Format of data pixels. /// Data pixels. - public ImmutableBitmap(int width, int height, int stride, PixelFormat format, IntPtr data) + public ImmutableBitmap(PixelSize size, Vector dpi, int stride, PixelFormat format, IntPtr data) { - var imageInfo = new SKImageInfo(width, height, format.ToSkColorType(), SKAlphaType.Premul); + var imageInfo = new SKImageInfo(size.Width, size.Height, format.ToSkColorType(), SKAlphaType.Premul); _image = SKImage.FromPixelCopy(imageInfo, data, stride); @@ -55,15 +57,12 @@ namespace Avalonia.Skia throw new ArgumentException("Unable to create bitmap from provided data"); } - PixelWidth = width; - PixelHeight = height; + PixelSize = size; + Dpi = dpi; } - /// - public int PixelWidth { get; } - - /// - public int PixelHeight { get; } + public Vector Dpi { get; } + public PixelSize PixelSize { get; } /// public void Dispose() @@ -89,4 +88,4 @@ namespace Avalonia.Skia context.Canvas.DrawImage(_image, sourceRect, destRect, paint); } } -} \ No newline at end of file +} diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index d4e6403dc9..b6a674271c 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -49,34 +49,28 @@ namespace Avalonia.Skia } /// - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) { - return new ImmutableBitmap(width, height, stride, format, data); + return new ImmutableBitmap(size, dpi, stride, format, data); } /// - public IRenderTargetBitmapImpl CreateRenderTargetBitmap( - int width, - int height, - double dpiX, - double dpiY) + public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi) { - if (width < 1) + if (size.Width < 1) { - throw new ArgumentException("Width can't be less than 1", nameof(width)); + throw new ArgumentException("Width can't be less than 1", nameof(size)); } - if (height < 1) + if (size.Height < 1) { - throw new ArgumentException("Height can't be less than 1", nameof(height)); + throw new ArgumentException("Height can't be less than 1", nameof(size)); } - var dpi = new Vector(dpiX, dpiY); - var createInfo = new SurfaceRenderTarget.CreateInfo { - Width = width, - Height = height, + Width = size.Width, + Height = size.Height, Dpi = dpi, DisableTextLcdRendering = false }; @@ -100,9 +94,9 @@ namespace Avalonia.Skia } /// - public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) { - return new WriteableBitmapImpl(width, height, format); + return new WriteableBitmapImpl(size, dpi, format); } } -} \ No newline at end of file +} diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs index 88200dcfbe..e84c512796 100644 --- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs @@ -15,7 +15,6 @@ namespace Avalonia.Skia /// public class SurfaceRenderTarget : IRenderTargetBitmapImpl, IDrawableBitmapImpl { - private readonly Vector _dpi; private readonly SKSurface _surface; private readonly SKCanvas _canvas; private readonly bool _disableLcdRendering; @@ -26,12 +25,11 @@ namespace Avalonia.Skia /// Create info. public SurfaceRenderTarget(CreateInfo createInfo) { - PixelWidth = createInfo.Width; - PixelHeight = createInfo.Height; - _dpi = createInfo.Dpi; - _disableLcdRendering = createInfo.DisableTextLcdRendering; + PixelSize = new PixelSize(createInfo.Width, createInfo.Height); + Dpi = createInfo.Dpi; - _surface = CreateSurface(PixelWidth, PixelHeight, createInfo.Format); + _disableLcdRendering = createInfo.DisableTextLcdRendering; + _surface = CreateSurface(PixelSize.Width, PixelSize.Height, createInfo.Format); _canvas = _surface?.Canvas; @@ -71,7 +69,7 @@ namespace Avalonia.Skia var createInfo = new DrawingContextImpl.CreateInfo { Canvas = _canvas, - Dpi = _dpi, + Dpi = Dpi, VisualBrushRenderer = visualBrushRenderer, DisableTextLcdRendering = _disableLcdRendering }; @@ -80,10 +78,10 @@ namespace Avalonia.Skia } /// - public int PixelWidth { get; } + public Vector Dpi { get; } /// - public int PixelHeight { get; } + public PixelSize PixelSize { get; } /// public void Save(string fileName) @@ -166,4 +164,4 @@ namespace Avalonia.Skia public bool DisableTextLcdRendering; } } -} \ No newline at end of file +} diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index ab6c399ff4..3abff10098 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -20,13 +20,13 @@ namespace Avalonia.Skia /// /// Create new writeable bitmap. /// - /// Width. - /// Height. - /// Format. - public WriteableBitmapImpl(int width, int height, PixelFormat? format = null) + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The pixel format. + public WriteableBitmapImpl(PixelSize size, Vector dpi, PixelFormat? format = null) { - PixelHeight = height; - PixelWidth = width; + PixelSize = size; + Dpi = dpi; var colorType = PixelFormatHelper.ResolveColorType(format); @@ -36,24 +36,23 @@ namespace Avalonia.Skia { _bitmap = new SKBitmap(); - var nfo = new SKImageInfo(width, height, colorType, SKAlphaType.Premul); + var nfo = new SKImageInfo(size.Width, size.Height, colorType, SKAlphaType.Premul); var blob = runtimePlatform.AllocBlob(nfo.BytesSize); _bitmap.InstallPixels(nfo, blob.Address, nfo.RowBytes, null, s_releaseDelegate, blob); } else { - _bitmap = new SKBitmap(width, height, colorType, SKAlphaType.Premul); + _bitmap = new SKBitmap(size.Width, size.Height, colorType, SKAlphaType.Premul); } _bitmap.Erase(SKColor.Empty); } - /// - public int PixelWidth { get; } + public Vector Dpi { get; } /// - public int PixelHeight { get; } + public PixelSize PixelSize { get; } /// public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint) @@ -133,10 +132,7 @@ namespace Avalonia.Skia public IntPtr Address => _bitmap.GetPixels(); /// - public int Width => _bitmap.Width; - - /// - public int Height => _bitmap.Height; + public PixelSize Size => new PixelSize(_bitmap.Width, _bitmap.Height); /// public int RowBytes => _bitmap.RowBytes; @@ -148,4 +144,4 @@ namespace Avalonia.Skia public PixelFormat Format => _bitmap.ColorType.ToPixelFormat(); } } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index c330377e20..3ec18dac5e 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -110,9 +110,9 @@ namespace Avalonia.Direct2D1 SharpDX.Configuration.EnableReleaseOnFinalizer = true; } - public IBitmapImpl CreateBitmap(int width, int height) + public IBitmapImpl CreateBitmap(PixelSize size, Vector dpi) { - return new WicBitmapImpl(width, height); + return new WicBitmapImpl(size, dpi); } public IFormattedTextImpl CreateFormattedText( @@ -159,18 +159,14 @@ namespace Avalonia.Direct2D1 throw new NotSupportedException("Don't know how to create a Direct2D1 renderer from any of provided surfaces"); } - public IRenderTargetBitmapImpl CreateRenderTargetBitmap( - int width, - int height, - double dpiX, - double dpiY) + public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi) { - return new WicRenderTargetBitmapImpl(width, height, dpiX, dpiY); + return new WicRenderTargetBitmapImpl(size, dpi); } - public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = null) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null) { - return new WriteableWicBitmapImpl(width, height, format); + return new WriteableWicBitmapImpl(size, dpi, format); } public IStreamGeometryImpl CreateStreamGeometry() @@ -188,9 +184,9 @@ namespace Avalonia.Direct2D1 return new WicBitmapImpl(stream); } - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) { - return new WicBitmapImpl(format, data, width, height, stride); + return new WicBitmapImpl(format, data, size, dpi, stride); } } } diff --git a/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs index 5ae174083c..f7e7ed3dc2 100644 --- a/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs +++ b/src/Windows/Avalonia.Direct2D1/FramebufferShimRenderTarget.cs @@ -40,7 +40,7 @@ namespace Avalonia.Direct2D1 private readonly ILockedFramebuffer _target; public FramebufferShim(ILockedFramebuffer target) : - base(target.Width, target.Height, target.Dpi.X, target.Dpi.Y, target.Format) + base(target.Size, target.Dpi, target.Format) { _target = target; } @@ -51,7 +51,7 @@ namespace Avalonia.Direct2D1 { using (var l = WicImpl.Lock(BitmapLockFlags.Read)) { - for (var y = 0; y < _target.Height; y++) + for (var y = 0; y < _target.Size.Height; y++) { UnmanagedMethods.CopyMemory( (_target.Address + _target.RowBytes * y), diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index b842f26edb..efe26ba01a 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -330,12 +330,8 @@ namespace Avalonia.Direct2D1.Media { var platform = AvaloniaLocator.Current.GetService(); var dpi = new Vector(_deviceContext.DotsPerInch.Width, _deviceContext.DotsPerInch.Height); - var pixelSize = size * (dpi / 96); - return platform.CreateRenderTargetBitmap( - (int)pixelSize.Width, - (int)pixelSize.Height, - dpi.X, - dpi.Y); + var pixelSize = PixelSize.FromSize(size, dpi); + return platform.CreateRenderTargetBitmap(pixelSize, dpi); } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs index 3fc8760a9e..55877cefcb 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs @@ -20,7 +20,7 @@ namespace Avalonia.Direct2D1.Media BitmapImpl bitmap, Size targetSize) { - var calc = new TileBrushCalculator(brush, new Size(bitmap.PixelWidth, bitmap.PixelHeight), targetSize); + var calc = new TileBrushCalculator(brush, bitmap.PixelSize.ToSize(96), targetSize); if (!calc.NeedsIntermediate) { @@ -99,7 +99,7 @@ namespace Avalonia.Direct2D1.Media using (var context = new RenderTarget(result).CreateDrawingContext(null)) { - var rect = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight); + var rect = new Rect(0, 0, bitmap.PixelSize.Width, bitmap.PixelSize.Height); context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs index 30af01283a..f3879b4eff 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs @@ -7,8 +7,8 @@ namespace Avalonia.Direct2D1.Media { public abstract class BitmapImpl : IBitmapImpl, IDisposable { - public abstract int PixelWidth { get; } - public abstract int PixelHeight { get; } + public abstract Vector Dpi { get; } + public abstract PixelSize PixelSize { get; } public abstract OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target); diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs index b0edb9c3bf..1ee869ecb9 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs @@ -30,8 +30,8 @@ namespace Avalonia.Direct2D1.Media _direct2DBitmap = d2DBitmap ?? throw new ArgumentNullException(nameof(d2DBitmap)); } - public override int PixelWidth => _direct2DBitmap.PixelSize.Width; - public override int PixelHeight => _direct2DBitmap.PixelSize.Height; + public override Vector Dpi => _direct2DBitmap.DotsPerInch.ToAvaloniaVector(); + public override PixelSize PixelSize => _direct2DBitmap.PixelSize.ToAvalonia(); public override void Dispose() { diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs index 3646d9e9e1..88602b935e 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs @@ -19,9 +19,6 @@ namespace Avalonia.Direct2D1.Media.Imaging _renderTarget = renderTarget; } - public override int PixelWidth => _renderTarget.PixelSize.Width; - public override int PixelHeight => _renderTarget.PixelSize.Height; - public static D2DRenderTargetBitmapImpl CreateCompatible( SharpDX.Direct2D1.RenderTarget renderTarget, Size size) diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index b16ea45fc6..89b96953ad 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -42,10 +42,10 @@ namespace Avalonia.Direct2D1.Media /// /// Initializes a new instance of the class. /// - /// The width of the bitmap. - /// The height of the bitmap. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. /// Pixel format - public WicBitmapImpl(int width, int height, APixelFormat? pixelFormat = null) + public WicBitmapImpl(PixelSize size, Vector dpi, APixelFormat? pixelFormat = null) { if (!pixelFormat.HasValue) { @@ -55,19 +55,22 @@ namespace Avalonia.Direct2D1.Media PixelFormat = pixelFormat; WicImpl = new Bitmap( Direct2D1Platform.ImagingFactory, - width, - height, + size.Width, + size.Height, pixelFormat.Value.ToWic(), BitmapCreateCacheOption.CacheOnLoad); + WicImpl.SetResolution(dpi.X, dpi.Y); } - public WicBitmapImpl(APixelFormat format, IntPtr data, int width, int height, int stride) + public WicBitmapImpl(APixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) { - WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, width, height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand); + WicImpl = new Bitmap(Direct2D1Platform.ImagingFactory, size.Width, size.Height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand); + WicImpl.SetResolution(dpi.X, dpi.Y); + PixelFormat = format; using (var l = WicImpl.Lock(BitmapLockFlags.Write)) { - for (var row = 0; row < height; row++) + for (var row = 0; row < size.Height; row++) { UnmanagedMethods.CopyMemory( (l.Data.DataPointer + row * l.Stride), @@ -77,17 +80,18 @@ namespace Avalonia.Direct2D1.Media } } - protected APixelFormat? PixelFormat { get; } + public override Vector Dpi + { + get + { + WicImpl.GetResolution(out double x, out double y); + return new Vector(x, y); + } + } - /// - /// Gets the width of the bitmap, in pixels. - /// - public override int PixelWidth => WicImpl.Size.Width; + public override PixelSize PixelSize => WicImpl.Size.ToAvalonia(); - /// - /// Gets the height of the bitmap, in pixels. - /// - public override int PixelHeight => WicImpl.Size.Height; + protected APixelFormat? PixelFormat { get; } public override void Dispose() { diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs index aa8b3ead42..ca441e7b69 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs @@ -13,17 +13,15 @@ namespace Avalonia.Direct2D1.Media private readonly WicRenderTarget _renderTarget; public WicRenderTargetBitmapImpl( - int width, - int height, - double dpiX, - double dpiY, + PixelSize size, + Vector dpi, Platform.PixelFormat? pixelFormat = null) - : base(width, height, pixelFormat) + : base(size, dpi, pixelFormat) { var props = new RenderTargetProperties { - DpiX = (float)dpiX, - DpiY = (float)dpiY, + DpiX = (float)dpi.X, + DpiY = (float)dpi.Y, }; _renderTarget = new WicRenderTarget( diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs index 5ca78ef278..e3bd3b3218 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs @@ -10,8 +10,8 @@ namespace Avalonia.Direct2D1.Media.Imaging { class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl { - public WriteableWicBitmapImpl(int width, int height, PixelFormat? pixelFormat) - : base(width, height, pixelFormat) + public WriteableWicBitmapImpl(PixelSize size, Vector dpi, PixelFormat? pixelFormat) + : base(size, dpi, pixelFormat) { } @@ -33,8 +33,7 @@ namespace Avalonia.Direct2D1.Media.Imaging } public IntPtr Address => _lock.Data.DataPointer; - public int Width => _lock.Size.Width; - public int Height => _lock.Size.Height; + public PixelSize Size => _lock.Size.ToAvalonia(); public int RowBytes => _lock.Stride; public Vector Dpi { get; } = new Vector(96, 96); public PixelFormat Format => _format; diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs index 124e33c5a3..5209014271 100644 --- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs +++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs @@ -41,6 +41,10 @@ namespace Avalonia.Direct2D1 return new Rect(new Point(r.Left, r.Top), new Point(r.Right, r.Bottom)); } + public static PixelSize ToAvalonia(this Size2 p) => new PixelSize(p.Width, p.Height); + + public static Vector ToAvaloniaVector(this Size2F p) => new Vector(p.Width, p.Height); + public static RawRectangleF ToSharpDX(this Rect r) { return new RawRectangleF((float)r.X, (float)r.Y, (float)r.Right, (float)r.Bottom); diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs index 79340fa335..05fa9d9426 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs @@ -58,8 +58,7 @@ namespace Avalonia.Win32.Interop.Wpf } public IntPtr Address => _bitmap.BackBuffer; - public int Width => _bitmap.PixelWidth; - public int Height => _bitmap.PixelHeight; + public PixelSize Size => new PixelSize(_bitmap.PixelWidth, _bitmap.PixelHeight); public int RowBytes => _bitmap.BackBufferStride; public Vector Dpi { get; } public PixelFormat Format => PixelFormat.Bgra8888; diff --git a/src/Windows/Avalonia.Win32/FramebufferManager.cs b/src/Windows/Avalonia.Win32/FramebufferManager.cs index bb0bde34ff..c910703181 100644 --- a/src/Windows/Avalonia.Win32/FramebufferManager.cs +++ b/src/Windows/Avalonia.Win32/FramebufferManager.cs @@ -21,11 +21,11 @@ namespace Avalonia.Win32 UnmanagedMethods.GetClientRect(_hwnd, out rc); var width = rc.right - rc.left; var height = rc.bottom - rc.top; - if ((_fb == null || _fb.Width != width || _fb.Height != height) && width > 0 && height > 0) + if ((_fb == null || _fb.Size.Width != width || _fb.Size.Height != height) && width > 0 && height > 0) { _fb?.Deallocate(); _fb = null; - _fb = new WindowFramebuffer(_hwnd, width, height); + _fb = new WindowFramebuffer(_hwnd, new PixelSize(width, height)); } return _fb; } diff --git a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs index 6193ebd02b..9c331f662d 100644 --- a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs +++ b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs @@ -11,21 +11,21 @@ namespace Avalonia.Win32 private IUnmanagedBlob _bitmapBlob; private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo; - public WindowFramebuffer(IntPtr handle, int width, int height) + public WindowFramebuffer(IntPtr handle, PixelSize size) { - if (width <= 0) - throw new ArgumentException("width is less than zero"); - if (height <= 0) - throw new ArgumentException("height is less than zero"); + if (size.Width <= 0) + throw new ArgumentException("Width is less than zero"); + if (size.Height <= 0) + throw new ArgumentException("Height is less than zero"); _handle = handle; _bmpInfo.Init(); _bmpInfo.biPlanes = 1; _bmpInfo.biBitCount = 32; _bmpInfo.Init(); - _bmpInfo.biWidth = width; - _bmpInfo.biHeight = -height; - _bitmapBlob = AvaloniaLocator.Current.GetService().AllocBlob(width * height * 4); + _bmpInfo.biWidth = size.Width; + _bmpInfo.biHeight = -size.Height; + _bitmapBlob = AvaloniaLocator.Current.GetService().AllocBlob(size.Width * size.Height * 4); } ~WindowFramebuffer() @@ -34,7 +34,7 @@ namespace Avalonia.Win32 } public IntPtr Address => _bitmapBlob.Address; - public int RowBytes => Width * 4; + public int RowBytes => Size.Width * 4; public PixelFormat Format => PixelFormat.Bgra8888; public Vector Dpi @@ -61,19 +61,17 @@ namespace Avalonia.Win32 } } - public int Width => _bmpInfo.biWidth; - - public int Height => -_bmpInfo.biHeight; + public PixelSize Size => new PixelSize(_bmpInfo.biWidth, _bmpInfo.biHeight); public void DrawToDevice(IntPtr hDC, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1, int height = -1) { if (width == -1) - width = Width; + width = Size.Width; if (height == -1) - height = Height; + height = Size.Height; UnmanagedMethods.SetDIBitsToDevice(hDC, destX, destY, (uint) width, (uint) height, srcX, srcY, - 0, (uint)Height, _bitmapBlob.Address, ref _bmpInfo, 0); + 0, (uint)Size.Height, _bitmapBlob.Address, ref _bmpInfo, 0); } public bool DrawToWindow(IntPtr hWnd, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1, diff --git a/tests/Avalonia.Controls.UnitTests/ImageTests.cs b/tests/Avalonia.Controls.UnitTests/ImageTests.cs index 7f2b5e77f9..7a0e5681d7 100644 --- a/tests/Avalonia.Controls.UnitTests/ImageTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ImageTests.cs @@ -13,7 +13,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_No_Stretch() { - var bitmap = Mock.Of(x => x.PixelWidth == 50 && x.PixelHeight == 100); + var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); var target = new Image(); target.Stretch = Stretch.None; target.Source = bitmap; @@ -26,7 +26,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_Fill_Stretch() { - var bitmap = Mock.Of(x => x.PixelWidth == 50 && x.PixelHeight == 100); + var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); var target = new Image(); target.Stretch = Stretch.Fill; target.Source = bitmap; @@ -39,7 +39,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_Uniform_Stretch() { - var bitmap = Mock.Of(x => x.PixelWidth == 50 && x.PixelHeight == 100); + var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); var target = new Image(); target.Stretch = Stretch.Uniform; target.Source = bitmap; @@ -52,7 +52,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_UniformToFill_Stretch() { - var bitmap = Mock.Of(x => x.PixelWidth == 50 && x.PixelHeight == 100); + var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); var target = new Image(); target.Stretch = Stretch.UniformToFill; target.Source = bitmap; diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs index 4cee05a0d9..e6cd800529 100644 --- a/tests/Avalonia.RenderTests/Media/BitmapTests.cs +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -29,14 +29,13 @@ namespace Avalonia.Direct2D1.RenderTests.Media class Framebuffer : ILockedFramebuffer, IFramebufferPlatformSurface { - public Framebuffer(PixelFormat fmt, int width, int height) + public Framebuffer(PixelFormat fmt, PixelSize size) { Format = fmt; var bpp = fmt == PixelFormat.Rgb565 ? 2 : 4; - Width = width; - Height = height; - RowBytes = bpp * width; - Address = Marshal.AllocHGlobal(Height * RowBytes); + Size = size; + RowBytes = bpp * size.Width; + Address = Marshal.AllocHGlobal(size.Height * RowBytes); } public IntPtr Address { get; } @@ -45,12 +44,10 @@ namespace Avalonia.Direct2D1.RenderTests.Media public PixelFormat Format { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } - public int Width { get; } - public void Dispose() { //no-op @@ -74,7 +71,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media public void FramebufferRenderResultsShouldBeUsableAsBitmap(PixelFormat fmt) { var testName = nameof(FramebufferRenderResultsShouldBeUsableAsBitmap) + "_" + fmt; - var fb = new Framebuffer(fmt, 80, 80); + var fb = new Framebuffer(fmt, new PixelSize(80, 80)); var r = Avalonia.AvaloniaLocator.Current.GetService(); using (var target = r.CreateRenderTarget(new object[] { fb })) using (var ctx = target.CreateDrawingContext(null)) @@ -87,9 +84,9 @@ namespace Avalonia.Direct2D1.RenderTests.Media ctx.PopOpacity(); } - var bmp = new Bitmap(fmt, fb.Address, fb.Width, fb.Height, fb.RowBytes); + var bmp = new Bitmap(fmt, fb.Address, fb.Size, new Vector(96, 96), fb.RowBytes); fb.Deallocate(); - using (var rtb = new RenderTargetBitmap(100, 100)) + using (var rtb = new RenderTargetBitmap(new PixelSize(100, 100), new Vector(96, 96))) { using (var ctx = rtb.CreateDrawingContext(null)) { @@ -108,7 +105,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media [InlineData(PixelFormat.Bgra8888), InlineData(PixelFormat.Rgba8888)] public void WriteableBitmapShouldBeUsable(PixelFormat fmt) { - var writeableBitmap = new WriteableBitmap(256, 256, fmt); + var writeableBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), fmt); var data = new int[256 * 256]; for (int y = 0; y < 256; y++) diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index 19413b32eb..2892615e48 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -73,22 +73,21 @@ namespace Avalonia.Direct2D1.RenderTests var immediatePath = Path.Combine(OutputPath, testName + ".immediate.out.png"); var deferredPath = Path.Combine(OutputPath, testName + ".deferred.out.png"); var factory = AvaloniaLocator.Current.GetService(); + var pixelSize = new PixelSize((int)target.Width, (int)target.Height); + var size = new Size(target.Width, target.Height); + var dpi = new Vector(96, 96); - using (RenderTargetBitmap bitmap = new RenderTargetBitmap( - (int)target.Width, - (int)target.Height)) + using (RenderTargetBitmap bitmap = new RenderTargetBitmap(pixelSize, dpi)) { - Size size = new Size(target.Width, target.Height); target.Measure(size); target.Arrange(new Rect(size)); bitmap.Render(target); bitmap.Save(immediatePath); } - using (var rtb = factory.CreateRenderTargetBitmap((int)target.Width, (int)target.Height, 96, 96)) + using (var rtb = factory.CreateRenderTargetBitmap(pixelSize, dpi)) using (var renderer = new DeferredRenderer(target, rtb)) { - Size size = new Size(target.Width, target.Height); target.Measure(size); target.Arrange(new Rect(size)); renderer.UnitTestUpdateScene(); diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index de2b517956..f8ad7e63f2 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -25,11 +25,7 @@ namespace Avalonia.UnitTests return Mock.Of(); } - public IRenderTargetBitmapImpl CreateRenderTargetBitmap( - int width, - int height, - double dpiX, - double dpiY) + public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi) { return Mock.Of(); } @@ -39,7 +35,10 @@ namespace Avalonia.UnitTests return new MockStreamGeometryImpl(); } - public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = default(PixelFormat?)) + public IWriteableBitmapImpl CreateWriteableBitmap( + PixelSize size, + Vector dpi, + PixelFormat? format = default(PixelFormat?)) { throw new NotImplementedException(); } @@ -54,7 +53,12 @@ namespace Avalonia.UnitTests return Mock.Of(); } - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + public IBitmapImpl LoadBitmap( + PixelFormat format, + IntPtr data, + PixelSize size, + Vector dpi, + int stride) { throw new NotImplementedException(); } diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index 93b5a8a764..92c12c6b9e 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -24,7 +24,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } - public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height, double dpiX, double dpiY) + public IRenderTargetBitmapImpl CreateRenderTargetBitmap(PixelSize size, Vector dpi) { throw new NotImplementedException(); } @@ -44,12 +44,12 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } - public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, Vector dpi, int stride) { throw new NotImplementedException(); } - public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? fmt) + public IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? fmt) { throw new NotImplementedException(); } From 465b2cd0dab99911ed0a6dae04483dad51c41761 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Sep 2018 23:49:40 +0200 Subject: [PATCH 002/197] Add PixelSize to mobile APIs. --- .../Platform/SkiaPlatform/AndroidFramebuffer.cs | 8 ++++---- src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs | 12 +++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs index 405da12967..2afa4e83f1 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs @@ -20,9 +20,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform ANativeWindow_Buffer buffer; var rc = new ARect() { - right = Width = ANativeWindow_getWidth(_window), - bottom = Height = ANativeWindow_getHeight(_window) + right = ANativeWindow_getWidth(_window), + bottom = ANativeWindow_getHeight(_window) }; + Size = new PixelSize(rc.right, rc.bottom); ANativeWindow_lock(_window, out buffer, ref rc); Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565 @@ -41,8 +42,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform } public IntPtr Address { get; set; } - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } public Vector Dpi { get; } = new Vector(96, 96); public PixelFormat Format { get; } diff --git a/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs b/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs index b3b41fe724..89c7aaf76c 100644 --- a/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs +++ b/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs @@ -23,12 +23,11 @@ namespace Avalonia.iOS var frame = view.Frame; _viewWidth = frame.Width; _viewHeight = frame.Height; - Width = (int) frame.Width * factor; - Height = (int) frame.Height * factor; - RowBytes = Width * 4; + Size = new PixelSize((int)frame.Width * factor, (int)frame.Height * factor); + RowBytes = Size.Width * 4; Dpi = new Vector(96, 96) * factor; Format = PixelFormat.Rgba8888; - Address = Marshal.AllocHGlobal(Height * RowBytes); + Address = Marshal.AllocHGlobal(Size.Height * RowBytes); } public void Dispose() @@ -37,7 +36,7 @@ namespace Avalonia.iOS return; var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast; using (var colorSpace = CGColorSpace.CreateDeviceRGB()) - using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, + using (var bContext = new CGBitmapContext(Address, Size.Width, Size.Height, 8, Size.Width * 4, colorSpace, (CGImageAlphaInfo) nfo)) using (var image = bContext.ToImage()) using (var context = UIGraphics.GetCurrentContext()) @@ -52,8 +51,7 @@ namespace Avalonia.iOS } public IntPtr Address { get; private set; } - public int Width { get; } - public int Height { get; } + public PixelSize Size { get; } public int RowBytes { get; } public Vector Dpi { get; } public PixelFormat Format { get; } From 0de606b995353ebf215db6ef785648db4096b8ff Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 11 Sep 2018 23:57:50 +0200 Subject: [PATCH 003/197] Fix failing tests. --- tests/Avalonia.Controls.UnitTests/ImageTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/ImageTests.cs b/tests/Avalonia.Controls.UnitTests/ImageTests.cs index 7a0e5681d7..e92fc572b4 100644 --- a/tests/Avalonia.Controls.UnitTests/ImageTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ImageTests.cs @@ -13,7 +13,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_No_Stretch() { - var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); + var bitmap = Mock.Of(x => x.PixelSize == new PixelSize(50, 100)); var target = new Image(); target.Stretch = Stretch.None; target.Source = bitmap; @@ -26,7 +26,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_Fill_Stretch() { - var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); + var bitmap = Mock.Of(x => x.PixelSize == new PixelSize(50, 100)); var target = new Image(); target.Stretch = Stretch.Fill; target.Source = bitmap; @@ -39,7 +39,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_Uniform_Stretch() { - var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); + var bitmap = Mock.Of(x => x.PixelSize == new PixelSize(50, 100)); var target = new Image(); target.Stretch = Stretch.Uniform; target.Source = bitmap; @@ -52,7 +52,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void Measure_Should_Return_Correct_Size_For_UniformToFill_Stretch() { - var bitmap = Mock.Of(x => x.Size == new Size(50, 100)); + var bitmap = Mock.Of(x => x.PixelSize == new PixelSize(50, 100)); var target = new Image(); target.Stretch = Stretch.UniformToFill; target.Source = bitmap; From be8d4516b9af7e20e9587413f245b2a070d4536d Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Thu, 11 Oct 2018 10:11:42 +0300 Subject: [PATCH 004/197] unit test for Listbox OutOfRangeException issue #1395 --- .../ListBoxTests.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index 1debccd3c5..bc563c25e2 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -196,6 +196,41 @@ namespace Avalonia.Controls.UnitTests target.Presenter.Panel.Children.Cast().Select(x => (string)x.Content)); } + + [Fact] + public void ListBox_After_Scroll_IndexOutOfRangeException_Shouldnt_Be_Thrown() + { + var items = Enumerable.Range(0, 11).Select(x => $"{x}").ToArray(); + + var target = new ListBox + { + Template = ListBoxTemplate(), + Items = items, + ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 11 }) + }; + + Prepare(target); + + var panel = target.Presenter.Panel as IVirtualizingPanel; + + var listBoxItems = panel.Children.OfType(); + + //virtualization should have created exactly 10 items + Assert.Equal(10, listBoxItems.Count()); + Assert.Equal("0", listBoxItems.First().DataContext); + Assert.Equal("9", listBoxItems.Last().DataContext); + + //instead pixeloffset > 0 there could be pretty complex sequence for repro + //it involves add/remove/scroll to end multiple actions + //which i can't find so far :(, but this is the simplest way to add it to unit test + panel.PixelOffset = 1; + + //here scroll to end -> IndexOutOfRangeException is thrown + target.Scroll.Offset = new Vector(0, 2); + + Assert.True(true); + } + private FuncControlTemplate ListBoxTemplate() { return new FuncControlTemplate(parent => From 092a7c965aade6d849212f7a946d01c0e2f5ad3f Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Thu, 11 Oct 2018 11:44:31 +0300 Subject: [PATCH 005/197] fix for ListBox OutOfRangeException issue #1395 --- .../Presenters/ItemVirtualizerSimple.cs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs index f31a48b2a0..374066dfad 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs +++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs @@ -76,9 +76,23 @@ namespace Avalonia.Controls.Presenters var firstIndex = ItemCount - panel.Children.Count; RecycleContainersForMove(firstIndex - FirstIndex); - panel.PixelOffset = VirtualizingPanel.ScrollDirection == Orientation.Vertical ? - panel.Children[0].Bounds.Height : - panel.Children[0].Bounds.Width; + double pixelOffset; + var child = panel.Children[0]; + + if (child.IsArrangeValid) + { + pixelOffset = VirtualizingPanel.ScrollDirection == Orientation.Vertical ? + child.Bounds.Height : + child.Bounds.Width; + } + else + { + pixelOffset = VirtualizingPanel.ScrollDirection == Orientation.Vertical ? + child.DesiredSize.Height : + child.DesiredSize.Width; + } + + panel.PixelOffset = pixelOffset; } } } @@ -402,6 +416,20 @@ namespace Avalonia.Controls.Presenters var panel = VirtualizingPanel; var generator = Owner.ItemContainerGenerator; var selector = Owner.MemberSelector; + + //validate delta it should never overflow last index or generate index < 0 + if (delta > 0) + { + if ((FirstIndex + delta + panel.Children.Count) > ItemCount) + { + delta = ItemCount - FirstIndex - panel.Children.Count; + } + } + else if ((FirstIndex + delta) < 0) + { + delta = -FirstIndex; + } + var sign = delta < 0 ? -1 : 1; var count = Math.Min(Math.Abs(delta), panel.Children.Count); var move = count < panel.Children.Count; From 5c74c49a0a6dc781044f75eda02ede64bcd61d35 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Mon, 15 Oct 2018 22:37:10 +0300 Subject: [PATCH 006/197] pr notes --- src/Avalonia.Base/Utilities/MathUtilities.cs | 24 ++++++++++++++++++- .../Presenters/ItemVirtualizerSimple.cs | 12 +--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs index ab21e5fda0..dcb3ef4a2b 100644 --- a/src/Avalonia.Base/Utilities/MathUtilities.cs +++ b/src/Avalonia.Base/Utilities/MathUtilities.cs @@ -1,7 +1,6 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. - namespace Avalonia.Utilities { /// @@ -31,5 +30,28 @@ namespace Avalonia.Utilities return val; } } + + /// + /// Clamps a value between a minimum and maximum value. + /// + /// The value. + /// The minimum value. + /// The maximum value. + /// The clamped value. + public static int Clamp(int val, int min, int max) + { + if (val < min) + { + return min; + } + else if (val > max) + { + return max; + } + else + { + return val; + } + } } } diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs index 374066dfad..b177dc50cf 100644 --- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs +++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs @@ -418,17 +418,7 @@ namespace Avalonia.Controls.Presenters var selector = Owner.MemberSelector; //validate delta it should never overflow last index or generate index < 0 - if (delta > 0) - { - if ((FirstIndex + delta + panel.Children.Count) > ItemCount) - { - delta = ItemCount - FirstIndex - panel.Children.Count; - } - } - else if ((FirstIndex + delta) < 0) - { - delta = -FirstIndex; - } + delta = MathUtilities.Clamp(delta, -FirstIndex, ItemCount - FirstIndex - panel.Children.Count); var sign = delta < 0 ? -1 : 1; var count = Math.Min(Math.Abs(delta), panel.Children.Count); From bb8549ef94bd7ef8c81455b218fdb7af0f610b7f Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Fri, 12 Oct 2018 17:03:16 +0300 Subject: [PATCH 007/197] listbox toggle selection not working unit test #1971 --- .../ListBoxTests.cs | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs index 1debccd3c5..ebfd56027d 100644 --- a/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ListBoxTests.cs @@ -1,13 +1,11 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using System; -using System.Collections.ObjectModel; using System.Linq; using Avalonia.Collections; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; -using Avalonia.Data; +using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Styling; using Avalonia.UnitTests; @@ -196,6 +194,45 @@ namespace Avalonia.Controls.UnitTests target.Presenter.Panel.Children.Cast().Select(x => (string)x.Content)); } + [Fact] + public void Toggle_Selection_Should_Update_Containers() + { + var items = Enumerable.Range(0, 10).Select(x => $"Item {x}").ToArray(); + var target = new ListBox + { + Template = ListBoxTemplate(), + Items = items, + SelectionMode = SelectionMode.Toggle, + ItemTemplate = new FuncDataTemplate(x => new TextBlock { Height = 10 }) + }; + + Prepare(target); + + var lbItems = target.GetLogicalChildren().OfType().ToArray(); + + var item = lbItems[0]; + + Assert.Equal(false, item.IsSelected); + + RaisePressedEvent(target, item, MouseButton.Left); + + Assert.Equal(true, item.IsSelected); + + RaisePressedEvent(target, item, MouseButton.Left); + + Assert.Equal(false, item.IsSelected); + } + + private void RaisePressedEvent(ListBox listBox, ListBoxItem item, MouseButton mouseButton) + { + listBox.RaiseEvent(new PointerPressedEventArgs + { + Source = item, + RoutedEvent = InputElement.PointerPressedEvent, + MouseButton = mouseButton + }); + } + private FuncControlTemplate ListBoxTemplate() { return new FuncControlTemplate(parent => From 889156df434cd59eccf267101ea470e68e62ab4e Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 16 Oct 2018 01:09:43 +0300 Subject: [PATCH 008/197] fixes #1971 listbox toggle selection --- .../Primitives/SelectingItemsControl.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index f8440aac47..ccbdc71b1d 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -62,7 +62,7 @@ namespace Avalonia.Controls.Primitives AvaloniaProperty.RegisterDirect( nameof(SelectedItem), o => o.SelectedItem, - (o, v) => o.SelectedItem = v, + (o, v) => o.SelectedItem = v, defaultBindingMode: BindingMode.TwoWay); /// @@ -88,7 +88,7 @@ namespace Avalonia.Controls.Primitives /// public static readonly RoutedEvent IsSelectedChangedEvent = RoutedEvent.Register( - "IsSelectedChanged", + "IsSelectedChanged", RoutingStrategies.Bubble); /// @@ -96,7 +96,7 @@ namespace Avalonia.Controls.Primitives /// public static readonly RoutedEvent SelectionChangedEvent = RoutedEvent.Register( - "SelectionChanged", + "SelectionChanged", RoutingStrategies.Bubble); private static readonly IList Empty = new object[0]; @@ -521,7 +521,7 @@ namespace Avalonia.Controls.Primitives else if (multi && range) { SynchronizeItems( - SelectedItems, + SelectedItems, GetRange(Items, SelectedIndex, index)); } else @@ -583,7 +583,7 @@ namespace Avalonia.Controls.Primitives } /// - /// Updates the selection based on an event that may have originated in a container that + /// Updates the selection based on an event that may have originated in a container that /// belongs to the control. /// /// The control that raised the event. @@ -595,7 +595,7 @@ namespace Avalonia.Controls.Primitives /// false. /// protected bool UpdateSelectionFromEventSource( - IInteractive eventSource, + IInteractive eventSource, bool select = true, bool rangeModifier = false, bool toggleModifier = false) @@ -807,12 +807,10 @@ namespace Avalonia.Controls.Primitives SelectedIndex = -1; } } - else + + foreach (var item in e.OldItems) { - foreach (var item in e.OldItems) - { - MarkItemSelected(item, false); - } + MarkItemSelected(item, false); } removed = e.OldItems; From a955f73a3e15303aac3b34e892c3963b1594a7af Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Fri, 19 Oct 2018 01:43:23 +0300 Subject: [PATCH 009/197] failing unittest for nested multibinding --- .../Data/MultiBindingTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs index fb23a38cce..78c538d99d 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs @@ -41,6 +41,37 @@ namespace Avalonia.Markup.UnitTests.Data Assert.Equal("1,2,3", result); } + [Fact] + public async Task Nested_MultiBinding_Should_Be_Set_Up() + { + var source = new { A = 1, B = 2, C = 3 }; + var binding = new MultiBinding + { + Converter = new ConcatConverter(), + Bindings = + { + new Binding { Path = "A" }, + new MultiBinding + { + Converter = new ConcatConverter(), + Bindings = + { + new Binding { Path = "B"}, + new Binding { Path = "C"} + } + } + } + }; + + var target = new Mock().As(); + target.Setup(x => x.GetValue(Control.DataContextProperty)).Returns(source); + + var observable = binding.Initiate(target.Object, null).Observable; + var result = await observable.Take(1); + + Assert.Equal("1,2,3", result); + } + [Fact] public void Should_Return_FallbackValue_When_Converter_Returns_UnsetValue() { From 0a5329f6a361b937aa2589fdf1ca93691a2a1cf5 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Fri, 19 Oct 2018 01:47:22 +0300 Subject: [PATCH 010/197] fix nested multibinding work again --- src/Markup/Avalonia.Markup/Data/MultiBinding.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 4c47ef32e0..4921b7c9d7 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -61,7 +61,7 @@ namespace Avalonia.Data var targetType = targetProperty?.PropertyType ?? typeof(object); var children = Bindings.Select(x => x.Initiate(target, null)); - var input = children.Select(x => x.Subject).CombineLatest().Select(x => ConvertValue(x, targetType)); + var input = children.Select(x => x.Observable).CombineLatest().Select(x => ConvertValue(x, targetType)); var mode = Mode == BindingMode.Default ? targetProperty?.GetMetadata(target.GetType()).DefaultBindingMode : Mode; From 41c2159aaab900fe59bac30796a7e9ca2dc2e53d Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 21 Oct 2018 17:51:21 +0200 Subject: [PATCH 011/197] Use features that are now available in netstandard. Various features were moved into `IRuntimePlatform` because they weren't available on netstandard 1.x. They're now available in netstandard 2 so use them directly. --- src/Avalonia.Base/Platform/IRuntimePlatform.cs | 3 --- src/Avalonia.Controls/AppBuilderBase.cs | 2 +- src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs | 4 ++-- src/Linux/Avalonia.LinuxFramebuffer/Mice.cs | 2 +- .../PortableXaml/AvaloniaRuntimeTypeProvider.cs | 4 +--- src/Shared/PlatformSupport/AssetLoader.cs | 2 +- src/Shared/PlatformSupport/StandardRuntimePlatform.cs | 4 ---- 7 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Base/Platform/IRuntimePlatform.cs b/src/Avalonia.Base/Platform/IRuntimePlatform.cs index 9adb98e689..a0d5d611b3 100644 --- a/src/Avalonia.Base/Platform/IRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/IRuntimePlatform.cs @@ -5,10 +5,7 @@ namespace Avalonia.Platform { public interface IRuntimePlatform { - Assembly[] GetLoadedAssemblies(); - void PostThreadPoolItem(Action cb); IDisposable StartSystemTimer(TimeSpan interval, Action tick); - string GetStackTrace(); RuntimePlatformInfo GetRuntimeInfo(); IUnmanagedBlob AllocBlob(int size); } diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 9561282274..376714b20b 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -222,7 +222,7 @@ namespace Avalonia.Controls private void SetupAvaloniaModules() { - var moduleInitializers = from assembly in AvaloniaLocator.Current.GetService().GetLoadedAssemblies() + var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies() from attribute in assembly.GetCustomAttributes() where attribute.ForWindowingSubsystem == "" || attribute.ForWindowingSubsystem == WindowingSubsystemName diff --git a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs index bae97f503d..fe791e156b 100644 --- a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs +++ b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs @@ -55,7 +55,7 @@ namespace Avalonia LoadAssembliesInDirectory(); - var windowingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies() + var windowingSubsystemAttribute = (from assembly in AppDomain.CurrentDomain.GetAssemblies() from attribute in assembly.GetCustomAttributes() where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker) orderby attribute.Priority ascending @@ -65,7 +65,7 @@ namespace Avalonia throw new InvalidOperationException("No windowing subsystem found. Are you missing assembly references?"); } - var renderingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies() + var renderingSubsystemAttribute = (from assembly in AppDomain.CurrentDomain.GetAssemblies() from attribute in assembly.GetCustomAttributes() where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker) where attribute.RequiresWindowingSubsystem == null diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Mice.cs b/src/Linux/Avalonia.LinuxFramebuffer/Mice.cs index 291374a75e..4fa57dbf00 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Mice.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Mice.cs @@ -22,7 +22,7 @@ namespace Avalonia.LinuxFramebuffer _height = height; } - public void Start() => AvaloniaLocator.Current.GetService().PostThreadPoolItem(Worker); + public void Start() => ThreadPool.UnsafeQueueUserWorkItem(_ => Worker(), null); private void Worker() { diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs index cdb5fc3416..eb52e317b8 100644 --- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs +++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaRuntimeTypeProvider.cs @@ -91,9 +91,7 @@ namespace Avalonia.Markup.Xaml.Context private void ScanNewAssemblies() { - IEnumerable assemblies = AvaloniaLocator.Current - .GetService() - ?.GetLoadedAssemblies(); + IEnumerable assemblies = AppDomain.CurrentDomain.GetAssemblies(); if (assemblies != null) { diff --git a/src/Shared/PlatformSupport/AssetLoader.cs b/src/Shared/PlatformSupport/AssetLoader.cs index d73c98415e..3392baee0a 100644 --- a/src/Shared/PlatformSupport/AssetLoader.cs +++ b/src/Shared/PlatformSupport/AssetLoader.cs @@ -157,7 +157,7 @@ namespace Avalonia.Shared.PlatformSupport AssemblyDescriptor rv; if (!AssemblyNameCache.TryGetValue(name, out rv)) { - var loadedAssemblies = AvaloniaLocator.Current.GetService().GetLoadedAssemblies(); + var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); var match = loadedAssemblies.FirstOrDefault(a => a.GetName().Name == name); if (match != null) { diff --git a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs b/src/Shared/PlatformSupport/StandardRuntimePlatform.cs index beed847539..613cf2baf6 100644 --- a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs +++ b/src/Shared/PlatformSupport/StandardRuntimePlatform.cs @@ -13,15 +13,11 @@ namespace Avalonia.Shared.PlatformSupport { internal partial class StandardRuntimePlatform : IRuntimePlatform { - public void PostThreadPoolItem(Action cb) => ThreadPool.UnsafeQueueUserWorkItem(_ => cb(), null); - public Assembly[] GetLoadedAssemblies() => AppDomain.CurrentDomain.GetAssemblies(); public IDisposable StartSystemTimer(TimeSpan interval, Action tick) { return new Timer(_ => tick(), null, interval, interval); } - public string GetStackTrace() => Environment.StackTrace; - public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size); class UnmanagedBlob : IUnmanagedBlob From da55b4b3eddf6613323cada6767a5a46f16b7f90 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sun, 21 Oct 2018 17:53:26 +0200 Subject: [PATCH 012/197] Don't pinvoke to compare threads. This was implemented in native code for netstandard 1, but now we can do it in managed code. Much faster. --- src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs | 3 --- src/Windows/Avalonia.Win32/Win32Platform.cs | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index c3c867d3fb..f0e2c1f689 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -751,9 +751,6 @@ namespace Avalonia.Win32.Interop [DllImport("kernel32.dll")] public static extern IntPtr GetModuleHandle(string lpModuleName); - [DllImport("kernel32.dll")] - public static extern uint GetCurrentThreadId(); - [DllImport("user32.dll")] public static extern int GetSystemMetrics(SystemMetric smIndex); diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index 33bee4a82a..4b9c0efde7 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -41,7 +41,7 @@ namespace Avalonia.Win32 class Win32Platform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform, IPlatformIconLoader { private static readonly Win32Platform s_instance = new Win32Platform(); - private static uint _uiThread; + private static Thread _uiThread; private UnmanagedMethods.WndProc _wndProcDelegate; private IntPtr _hwnd; private readonly List _delegates = new List(); @@ -93,7 +93,7 @@ namespace Avalonia.Win32 .Bind().ToConstant(s_instance); Win32GlManager.Initialize(); UseDeferredRendering = deferredRendering; - _uiThread = UnmanagedMethods.GetCurrentThreadId(); + _uiThread = Thread.CurrentThread; if (OleContext.Current != null) AvaloniaLocator.CurrentMutable.Bind().ToSingleton(); @@ -157,7 +157,7 @@ namespace Avalonia.Win32 new IntPtr(SignalL)); } - public bool CurrentThreadIsLoopThread => _uiThread == UnmanagedMethods.GetCurrentThreadId(); + public bool CurrentThreadIsLoopThread => _uiThread == Thread.CurrentThread; public event Action Signaled; From d2be495bdecb5f249ff8855d6921fb14ba185a82 Mon Sep 17 00:00:00 2001 From: artyom Date: Sun, 21 Oct 2018 20:56:55 +0300 Subject: [PATCH 013/197] Add ReactiveUserControl and ReactiveWindow --- .../ReactiveUserControl.cs | 45 ++++++++++ src/Avalonia.ReactiveUI/ReactiveWindow.cs | 45 ++++++++++ .../AvaloniaActivationForViewFetcherTest.cs | 82 ++++++++++++++++--- 3 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 src/Avalonia.ReactiveUI/ReactiveUserControl.cs create mode 100644 src/Avalonia.ReactiveUI/ReactiveWindow.cs diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs new file mode 100644 index 0000000000..5df6399c38 --- /dev/null +++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs @@ -0,0 +1,45 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia; +using Avalonia.VisualTree; +using Avalonia.Controls; +using ReactiveUI; + +namespace Avalonia +{ + /// + /// A ReactiveUI UserControl that implements + /// and will activate your ViewModel automatically if it supports activation. + /// + /// ViewModel type. + public class ReactiveUserControl : UserControl, IViewFor where TViewModel : class + { + public static readonly AvaloniaProperty ViewModelProperty = AvaloniaProperty + .Register, TViewModel>(nameof(ViewModel)); + + /// + /// Initializes a new instance of the class. + /// + public ReactiveUserControl() + { + DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; + this.WhenActivated(disposables => { /* activate ViewModel */ }); + } + + /// + /// The ViewModel. + /// + public TViewModel ViewModel + { + get => GetValue(ViewModelProperty); + set => SetValue(ViewModelProperty, value); + } + + object IViewFor.ViewModel + { + get => ViewModel; + set => ViewModel = (TViewModel)value; + } + } +} \ No newline at end of file diff --git a/src/Avalonia.ReactiveUI/ReactiveWindow.cs b/src/Avalonia.ReactiveUI/ReactiveWindow.cs new file mode 100644 index 0000000000..c8b0c59d67 --- /dev/null +++ b/src/Avalonia.ReactiveUI/ReactiveWindow.cs @@ -0,0 +1,45 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia; +using Avalonia.VisualTree; +using Avalonia.Controls; +using ReactiveUI; + +namespace Avalonia +{ + /// + /// A ReactiveUI Window that implements + /// and will activate your ViewModel automatically if it supports activation. + /// + /// ViewModel type. + public class ReactiveWindow : Window, IViewFor where TViewModel : class + { + public static readonly AvaloniaProperty ViewModelProperty = AvaloniaProperty + .Register, TViewModel>(nameof(ViewModel)); + + /// + /// Initializes a new instance of the class. + /// + public ReactiveWindow() + { + DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; + this.WhenActivated(disposables => { /* activate ViewModel */ }); + } + + /// + /// The ViewModel. + /// + public TViewModel ViewModel + { + get => GetValue(ViewModelProperty); + set => SetValue(ViewModelProperty, value); + } + + object IViewFor.ViewModel + { + get => ViewModel; + set => ViewModel = (TViewModel)value; + } + } +} \ No newline at end of file diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs index bda55276a8..cdf19c067d 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs @@ -23,7 +23,8 @@ namespace Avalonia public TestUserControlWithWhenActivated() { - this.WhenActivated(disposables => { + this.WhenActivated(disposables => + { Active = true; Disposable .Create(() => Active = false) @@ -38,7 +39,8 @@ namespace Avalonia public TestWindowWithWhenActivated() { - this.WhenActivated(disposables => { + this.WhenActivated(disposables => + { Active = true; Disposable .Create(() => Active = false) @@ -47,6 +49,42 @@ namespace Avalonia } } + public class ActivatableViewModel : ISupportsActivation + { + public ViewModelActivator Activator { get; } + + public bool IsActivated { get; private set; } + + public ActivatableViewModel() + { + Activator = new ViewModelActivator(); + this.WhenActivated(disposables => + { + IsActivated = true; + Disposable + .Create(() => IsActivated = false) + .DisposeWith(disposables); + }); + } + } + + public class ActivatableWindow : ReactiveWindow + { + public ActivatableWindow() { } + } + + public class ActivatableUserControl : ReactiveUserControl + { + public ActivatableUserControl() { } + } + + public AvaloniaActivationForViewFetcherTest() + { + Locator.CurrentMutable.RegisterConstant( + new AvaloniaActivationForViewFetcher(), + typeof(IActivationForViewFetcher)); + } + [Fact] public void Visual_Element_Is_Activated_And_Deactivated() { @@ -86,10 +124,6 @@ namespace Avalonia [Fact] public void Activation_For_View_Fetcher_Should_Support_When_Activated() { - Locator.CurrentMutable.RegisterConstant( - new AvaloniaActivationForViewFetcher(), - typeof(IActivationForViewFetcher)); - var userControl = new TestUserControlWithWhenActivated(); Assert.False(userControl.Active); @@ -104,10 +138,6 @@ namespace Avalonia [Fact] public void Activation_For_View_Fetcher_Should_Support_Windows() { - Locator.CurrentMutable.RegisterConstant( - new AvaloniaActivationForViewFetcher(), - typeof(IActivationForViewFetcher)); - using (var application = UnitTestApplication.Start(TestServices.MockWindowingPlatform)) { var window = new TestWindowWithWhenActivated(); @@ -120,5 +150,37 @@ namespace Avalonia Assert.False(window.Active); } } + + [Fact] + public void Activatable_Window_View_Model_Is_Activated_And_Deactivated() + { + using (var application = UnitTestApplication.Start(TestServices.MockWindowingPlatform)) + { + var viewModel = new ActivatableViewModel(); + var window = new ActivatableWindow { ViewModel = viewModel }; + Assert.False(viewModel.IsActivated); + + window.Show(); + Assert.True(viewModel.IsActivated); + + window.Close(); + Assert.False(viewModel.IsActivated); + } + } + + [Fact] + public void Activatable_User_Control_View_Model_Is_Activated_And_Deactivated() + { + var root = new TestRoot(); + var viewModel = new ActivatableViewModel(); + var control = new ActivatableUserControl { ViewModel = viewModel }; + Assert.False(viewModel.IsActivated); + + root.Child = control; + Assert.True(viewModel.IsActivated); + + root.Child = null; + Assert.False(viewModel.IsActivated); + } } } \ No newline at end of file From 07b93373718c6487e8f3ca90d10f5cc0e475b1e8 Mon Sep 17 00:00:00 2001 From: "azure-pipelines[bot]" Date: Sun, 21 Oct 2018 18:36:17 +0000 Subject: [PATCH 014/197] Set up CI with Azure Pipelines --- azure-pipelines.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..e95595bdd1 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,13 @@ +pool: + vmImage: 'Ubuntu 16.04' + +steps: +- task: cake-build.cake.cake-build-task.Cake@0 + displayName: 'Cake ' + inputs: + useBuildAgentNuGetExe: true + +- task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact: drop' + inputs: + PathtoPublish: artifacts/ From b77e4d768f7ee17879dff7a6667906bb7593fd97 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 19:47:06 +0100 Subject: [PATCH 015/197] inital attempt to build avalonia on azure. --- azure-pipelines.yml | 65 ++++++++++++++++++++++++++++++++++++--------- build.cake | 13 +++++++++ 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e95595bdd1..e94608d17a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,13 +1,54 @@ -pool: - vmImage: 'Ubuntu 16.04' +jobs: +- job: Linux + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: DotNetCoreInstaller@0 + inputs: + version: '2.1.403' + - script: | + export COREHOST_TRACE=0 + export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + export DOTNET_CLI_TELEMETRY_OPTOUT=1 + which dotnet + dotnet --info + dotnet tool install -g Cake.Tool --version 0.30.0 + export PATH="$PATH:$HOME/.dotnet/tools" + dotnet cake build.cake -Configuration="Release" -Target="Azure-Linux" + +- job: macOS + pool: + vmImage: 'xcode9-macos10.13' + steps: + - task: DotNetCoreInstaller@0 + inputs: + version: '2.1.403' + - script: | + export COREHOST_TRACE=0 + export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + export DOTNET_CLI_TELEMETRY_OPTOUT=1 + which dotnet + dotnet --info + dotnet tool install -g Cake.Tool --version 0.30.0 + export PATH="$PATH:$HOME/.dotnet/tools" + dotnet cake build.cake -Configuration="Release" -Target="Azure-OSX" -steps: -- task: cake-build.cake.cake-build-task.Cake@0 - displayName: 'Cake ' - inputs: - useBuildAgentNuGetExe: true - -- task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: drop' - inputs: - PathtoPublish: artifacts/ +- job: Windows + pool: + vmImage: 'vs2017-win2016' + steps: + - task: DotNetCoreInstaller@0 + inputs: + version: '2.1.403' + - script: | + set COREHOST_TRACE=0 + set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + set DOTNET_CLI_TELEMETRY_OPTOUT=1 + where dotnet + dotnet --info + dotnet tool install -g Cake.Tool --version 0.30.0 + set PATH=%PATH%;%USERPROFILE%\.dotnet\tools + dotnet cake build.cake -Configuration="Release" -Target="Azure-Windows" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: artifacts/ \ No newline at end of file diff --git a/build.cake b/build.cake index 56653109ae..74cd0057f1 100644 --- a/build.cake +++ b/build.cake @@ -377,6 +377,19 @@ Task("AppVeyor") Task("Travis") .IsDependentOn("Run-Tests"); +Task("Azure-Linux") + .IsDependentOn("Run-Tests"); + +Task("Azure-OSX") + .IsDependentOn("Run-Tests"); + +Task("Azure-Windows") + .IsDependentOn("Package") + .IsDependentOn("Copy-Files-Impl") + .IsDependentOn("Zip-Files-Impl") + .IsDependentOn("Publish-MyGet-Impl") + .IsDependentOn("Publish-NuGet-Impl"); + /////////////////////////////////////////////////////////////////////////////// // EXECUTE /////////////////////////////////////////////////////////////////////////////// From 8188f1d94d6fd2fe9b909c24f8c8aaa4b8cd5f9b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 19:49:40 +0100 Subject: [PATCH 016/197] nuget.core not needed? --- build.cake | 1 - 1 file changed, 1 deletion(-) diff --git a/build.cake b/build.cake index 74cd0057f1..8774b61324 100644 --- a/build.cake +++ b/build.cake @@ -2,7 +2,6 @@ // ADDINS /////////////////////////////////////////////////////////////////////////////// -#addin "nuget:?package=NuGet.Core&version=2.14.0" #tool "nuget:?package=NuGet.CommandLine&version=4.3.0" #tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2017.1.20170613.162720" From c315a50565ad68c7d00232675f21bd946acaf37f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 19:55:53 +0100 Subject: [PATCH 017/197] use original bootstrap cake scripts --- azure-pipelines.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e94608d17a..1a06c888ac 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,9 +12,7 @@ jobs: export DOTNET_CLI_TELEMETRY_OPTOUT=1 which dotnet dotnet --info - dotnet tool install -g Cake.Tool --version 0.30.0 - export PATH="$PATH:$HOME/.dotnet/tools" - dotnet cake build.cake -Configuration="Release" -Target="Azure-Linux" + ./build.sh --target "Azure-Linux" --configuration "Release" - job: macOS pool: @@ -29,9 +27,7 @@ jobs: export DOTNET_CLI_TELEMETRY_OPTOUT=1 which dotnet dotnet --info - dotnet tool install -g Cake.Tool --version 0.30.0 - export PATH="$PATH:$HOME/.dotnet/tools" - dotnet cake build.cake -Configuration="Release" -Target="Azure-OSX" + ./build.sh --target "Azure-OSX" --configuration "Release" - job: Windows pool: @@ -46,9 +42,7 @@ jobs: set DOTNET_CLI_TELEMETRY_OPTOUT=1 where dotnet dotnet --info - dotnet tool install -g Cake.Tool --version 0.30.0 - set PATH=%PATH%;%USERPROFILE%\.dotnet\tools - dotnet cake build.cake -Configuration="Release" -Target="Azure-Windows" + .\build.ps1 --target "Azure-Linux" --configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From ffadd1d0a33f2f7ac7e081b241e9f52d89bdbe37 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:06:19 +0100 Subject: [PATCH 018/197] update readme --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index f345cbd9df..6be9d30f50 100644 --- a/readme.md +++ b/readme.md @@ -2,9 +2,9 @@ # Avalonia -| Gitter Chat | Windows Build Status | Linux/Mac Build Status | Open Collective | -|---|---|---|---| -| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [![Build Status](https://travis-ci.org/AvaloniaUI/Avalonia.svg?branch=master)](https://travis-ci.org/AvaloniaUI/Avalonia) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | +| Gitter Chat | Build Status | Windows Build Status | Linux/Mac Build Status | Open Collective | +|---|---|---|---|---| +| [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) | [![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [![Build Status](https://travis-ci.org/AvaloniaUI/Avalonia.svg?branch=master)](https://travis-ci.org/AvaloniaUI/Avalonia) | [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) | ## About From fe76b4e536d73a7591c1d0ff8e339118152324b3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:12:22 +0100 Subject: [PATCH 019/197] manual submodule clone --- azure-pipelines.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1a06c888ac..3910d59cc2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,6 +7,7 @@ jobs: inputs: version: '2.1.403' - script: | + git submodule update --init export COREHOST_TRACE=0 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 @@ -22,6 +23,7 @@ jobs: inputs: version: '2.1.403' - script: | + git submodule update --init export COREHOST_TRACE=0 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 @@ -37,6 +39,7 @@ jobs: inputs: version: '2.1.403' - script: | + git submodule update --init set COREHOST_TRACE=0 set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 set DOTNET_CLI_TELEMETRY_OPTOUT=1 From 5e1fd7945652718d4603379d7149f4cd67b89d67 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:30:03 +0100 Subject: [PATCH 020/197] dont manually clone submodules --- azure-pipelines.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3910d59cc2..1a06c888ac 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,7 +7,6 @@ jobs: inputs: version: '2.1.403' - script: | - git submodule update --init export COREHOST_TRACE=0 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 @@ -23,7 +22,6 @@ jobs: inputs: version: '2.1.403' - script: | - git submodule update --init export COREHOST_TRACE=0 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 @@ -39,7 +37,6 @@ jobs: inputs: version: '2.1.403' - script: | - git submodule update --init set COREHOST_TRACE=0 set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 set DOTNET_CLI_TELEMETRY_OPTOUT=1 From f339447de0178b79a753917dbad653d36508413e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:34:48 +0100 Subject: [PATCH 021/197] fix windows build? --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1a06c888ac..8a0b9fc731 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -42,7 +42,7 @@ jobs: set DOTNET_CLI_TELEMETRY_OPTOUT=1 where dotnet dotnet --info - .\build.ps1 --target "Azure-Linux" --configuration "Release" + build.ps1 --target "Azure-Linux" --configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From fcda1bc519c7816a67f973da68f0b5a7c0fb2445 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:45:48 +0100 Subject: [PATCH 022/197] do not install dotnet. use azure powershell tasks --- azure-pipelines.yml | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8a0b9fc731..cab59085a4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,14 +3,7 @@ jobs: pool: vmImage: 'ubuntu-16.04' steps: - - task: DotNetCoreInstaller@0 - inputs: - version: '2.1.403' - script: | - export COREHOST_TRACE=0 - export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - export DOTNET_CLI_TELEMETRY_OPTOUT=1 - which dotnet dotnet --info ./build.sh --target "Azure-Linux" --configuration "Release" @@ -18,14 +11,7 @@ jobs: pool: vmImage: 'xcode9-macos10.13' steps: - - task: DotNetCoreInstaller@0 - inputs: - version: '2.1.403' - script: | - export COREHOST_TRACE=0 - export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - export DOTNET_CLI_TELEMETRY_OPTOUT=1 - which dotnet dotnet --info ./build.sh --target "Azure-OSX" --configuration "Release" @@ -33,16 +19,9 @@ jobs: pool: vmImage: 'vs2017-win2016' steps: - - task: DotNetCoreInstaller@0 + - task: PowerShell@2 inputs: - version: '2.1.403' - - script: | - set COREHOST_TRACE=0 - set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - set DOTNET_CLI_TELEMETRY_OPTOUT=1 - where dotnet - dotnet --info - build.ps1 --target "Azure-Linux" --configuration "Release" + script: build.ps1 --target "Azure-Linux" --configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From d769969dec33d89950a2434695c09110783e0326 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:48:06 +0100 Subject: [PATCH 023/197] fix powershell task --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cab59085a4..17d1ed18a9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,7 +21,8 @@ jobs: steps: - task: PowerShell@2 inputs: - script: build.ps1 --target "Azure-Linux" --configuration "Release" + filePath: build.ps1 + arguments: --target "Azure-Linux" --configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From 9f297ec1580d09c40923f504bfe036e898413fdc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:50:50 +0100 Subject: [PATCH 024/197] fix powershell --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 17d1ed18a9..a2b0f7eff0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,8 +21,8 @@ jobs: steps: - task: PowerShell@2 inputs: - filePath: build.ps1 - arguments: --target "Azure-Linux" --configuration "Release" + targetType: inline + script: build.ps1 --target "Azure-Linux" --configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From b74aa092a4be80b4936cf236629960e04a0f7049 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:52:25 +0100 Subject: [PATCH 025/197] fix powershell' --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a2b0f7eff0..e1110051f4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: - task: PowerShell@2 inputs: targetType: inline - script: build.ps1 --target "Azure-Linux" --configuration "Release" + script: .\build.ps1 --target "Azure-Linux" --configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From f9794406436d57a817ba209423fda33485e7052e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:54:28 +0100 Subject: [PATCH 026/197] fix argument passing --- azure-pipelines.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e1110051f4..a19c556555 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,8 +21,9 @@ jobs: steps: - task: PowerShell@2 inputs: - targetType: inline - script: .\build.ps1 --target "Azure-Linux" --configuration "Release" + targetType: + filePath: build.ps1 + arguments: -target "Azure-Linux" -configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From 5548e983da59d8a0671242ac2fd487eb0e2e7c4b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 20:57:17 +0100 Subject: [PATCH 027/197] fix powershell --- azure-pipelines.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a19c556555..14f54bf79b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,7 +21,6 @@ jobs: steps: - task: PowerShell@2 inputs: - targetType: filePath: build.ps1 arguments: -target "Azure-Linux" -configuration "Release" - task: PublishBuildArtifacts@1 From bafa8cc97e21617b1018182efbcc3698c63787c6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 21:03:30 +0100 Subject: [PATCH 028/197] dont publish packages --- build.cake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build.cake b/build.cake index 8774b61324..c729a4bb8d 100644 --- a/build.cake +++ b/build.cake @@ -369,9 +369,7 @@ Task("Package") Task("AppVeyor") .IsDependentOn("Package") .IsDependentOn("Copy-Files-Impl") - .IsDependentOn("Zip-Files-Impl") - .IsDependentOn("Publish-MyGet-Impl") - .IsDependentOn("Publish-NuGet-Impl"); + .IsDependentOn("Zip-Files-Impl"); Task("Travis") .IsDependentOn("Run-Tests"); @@ -386,8 +384,6 @@ Task("Azure-Windows") .IsDependentOn("Package") .IsDependentOn("Copy-Files-Impl") .IsDependentOn("Zip-Files-Impl") - .IsDependentOn("Publish-MyGet-Impl") - .IsDependentOn("Publish-NuGet-Impl"); /////////////////////////////////////////////////////////////////////////////// // EXECUTE From 65a00f69fac908b56e4a4374e13e9a6947a33924 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 21:12:09 +0100 Subject: [PATCH 029/197] fix windows build --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 14f54bf79b..3ae13d6d2f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: - task: PowerShell@2 inputs: filePath: build.ps1 - arguments: -target "Azure-Linux" -configuration "Release" + arguments: -target "Azure-Windows" -configuration "Release" - task: PublishBuildArtifacts@1 inputs: pathToPublish: artifacts/ \ No newline at end of file From 1f91578379ce74aae8d5106aa5b226e9a2d24b82 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 21:18:55 +0100 Subject: [PATCH 030/197] missing ; --- build.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.cake b/build.cake index c729a4bb8d..7420e9923b 100644 --- a/build.cake +++ b/build.cake @@ -383,7 +383,7 @@ Task("Azure-OSX") Task("Azure-Windows") .IsDependentOn("Package") .IsDependentOn("Copy-Files-Impl") - .IsDependentOn("Zip-Files-Impl") + .IsDependentOn("Zip-Files-Impl"); /////////////////////////////////////////////////////////////////////////////// // EXECUTE From 930f15c45e5d5348d07441c176d2a49372f35df1 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Sun, 21 Oct 2018 13:49:09 -0700 Subject: [PATCH 031/197] Update azure-pipelines.yml --- azure-pipelines.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3ae13d6d2f..14923d9ccf 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,4 +25,9 @@ jobs: arguments: -target "Azure-Windows" -configuration "Release" - task: PublishBuildArtifacts@1 inputs: - pathToPublish: artifacts/ \ No newline at end of file + pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget' + artifactName: 'NuGet' + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: '$(Build.SourcesDirectory)/artifacts/zip' + artifactName: 'Samples' From bd231f0a24beb183cfb622c578ea0cf4fbaeda05 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 22:06:29 +0100 Subject: [PATCH 032/197] dont inspect code. --- build.cake | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/build.cake b/build.cake index 7420e9923b..5273bce302 100644 --- a/build.cake +++ b/build.cake @@ -310,42 +310,6 @@ Task("Publish-NuGet-Impl") Information("Publish-NuGet Task failed, but continuing with next Task..."); }); -Task("Inspect-Impl") - .WithCriteria((context, data) => data.Parameters.IsRunningOnWindows) - .Does(() => -{ - var badIssues = new []{"PossibleNullReferenceException"}; - var whitelist = new []{"tests", "src\\android", "src\\ios", - "src\\markup\\avalonia.markup.xaml\\portablexaml\\portable.xaml.github"}; - Information("Running code inspections"); - - var exitCode = StartProcess(Context.Tools.Resolve("inspectcode.exe"), - new ProcessSettings - { - Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln", - RedirectStandardOutput = true - }); - - Information("Analyzing report"); - var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml")); - var failBuild = false; - foreach(var xml in doc.Descendants("Issue")) - { - var typeId = xml.Attribute("TypeId").Value.ToString(); - if(badIssues.Contains(typeId)) - { - var file = xml.Attribute("File").Value.ToString().ToLower(); - if(whitelist.Any(wh => file.StartsWith(wh))) - continue; - var line = xml.Attribute("Line").Value.ToString(); - Error(typeId + " - " + file + " on line " + line); - failBuild = true; - } - } - if(failBuild) - throw new Exception("Issues found"); -}); - /////////////////////////////////////////////////////////////////////////////// // TARGETS /////////////////////////////////////////////////////////////////////////////// @@ -363,7 +327,6 @@ Task("Run-Tests") Task("Package") .IsDependentOn("Run-Tests") - .IsDependentOn("Inspect-Impl") .IsDependentOn("Create-NuGet-Packages-Impl"); Task("AppVeyor") From 6c70b008973cca1c1e23bfb1b6028b7e7097c0e2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:06:28 +0100 Subject: [PATCH 033/197] build avalonia native osx part. --- azure-pipelines.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 14923d9ccf..2e59726c4b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,6 +11,15 @@ jobs: pool: vmImage: 'xcode9-macos10.13' steps: + - task: Xcode@5 + inputs: + actions: 'build' + scheme: '' + sdk: 'macosx10.13' + configuration: 'Release' + xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' + xcodeVersion: 'default' # Options: 8, 9, default, specifyPath + args: '-derivedDataPath ./' - script: | dotnet --info ./build.sh --target "Azure-OSX" --configuration "Release" From 7ddc683738b806a19b60af259eceb3aabe4345d8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 22:13:49 +0100 Subject: [PATCH 034/197] Revert "dont require osx dylib to be available." This reverts commit dc3b31d1061a7fae88b89823845d472c7af36a5b. --- src/Avalonia.Native/Avalonia.Native.csproj | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 3f334cffd3..8407a1b3f6 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -19,4 +19,13 @@ + + + + + runtimes/osx/native/libAvaloniaNative.dylib + true + PreserveNewest + + From b294e8a56d922b579392b879fac72d88253f363a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:16:26 +0100 Subject: [PATCH 035/197] install castxml. --- azure-pipelines.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2e59726c4b..071be42f55 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,6 +3,12 @@ jobs: pool: vmImage: 'ubuntu-16.04' steps: + - task: CmdLine@2 + inputs: + script: | + sudo apt-get update + sudo apt-get install castxml + - script: | dotnet --info ./build.sh --target "Azure-Linux" --configuration "Release" @@ -20,6 +26,11 @@ jobs: xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcodeVersion: 'default' # Options: 8, 9, default, specifyPath args: '-derivedDataPath ./' + + - task: CmdLine@2 + inputs: + script: brew install castxml + - script: | dotnet --info ./build.sh --target "Azure-OSX" --configuration "Release" From d8c0ca506f5418aa2636a2e3e3d4b5b9f8cd5e93 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:17:55 +0100 Subject: [PATCH 036/197] fix syntax --- azure-pipelines.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 071be42f55..1ad2d4cbe0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,9 +5,9 @@ jobs: steps: - task: CmdLine@2 inputs: - script: | - sudo apt-get update - sudo apt-get install castxml + script: | + sudo apt-get update + sudo apt-get install castxml - script: | dotnet --info @@ -28,8 +28,8 @@ jobs: args: '-derivedDataPath ./' - task: CmdLine@2 - inputs: - script: brew install castxml + inputs: + script: brew install castxml - script: | dotnet --info From ffefba1ea8137718d064057d9acb2cefa760efac Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:18:46 +0100 Subject: [PATCH 037/197] yaml!!!!!!!!!!!!!!! --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1ad2d4cbe0..bc2d7b2297 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,7 +29,7 @@ jobs: - task: CmdLine@2 inputs: - script: brew install castxml + script: brew install castxml - script: | dotnet --info From d2a637130931e8fc0dd697aa10d30b9c9d3d90f0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:20:46 +0100 Subject: [PATCH 038/197] yaml --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bc2d7b2297..bd1f1cdc63 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,7 +29,8 @@ jobs: - task: CmdLine@2 inputs: - script: brew install castxml + script: | + brew install castxml - script: | dotnet --info From 268055da0786a89af759a2f274b6008e24a7f94f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:22:37 +0100 Subject: [PATCH 039/197] yaml --- azure-pipelines.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bd1f1cdc63..509264e5e0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,12 +25,10 @@ jobs: configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcodeVersion: 'default' # Options: 8, 9, default, specifyPath - args: '-derivedDataPath ./' - + args: '-derivedDataPath ./' - task: CmdLine@2 inputs: - script: | - brew install castxml + script: brew install castxml - script: | dotnet --info From 3c44dce95c10f8d9f00fb0d75aaa3da2deef600f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:23:27 +0100 Subject: [PATCH 040/197] finally --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 509264e5e0..64334d991a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -27,8 +27,8 @@ jobs: xcodeVersion: 'default' # Options: 8, 9, default, specifyPath args: '-derivedDataPath ./' - task: CmdLine@2 - inputs: - script: brew install castxml + inputs: + script: brew install castxml - script: | dotnet --info From 50a158b41ece3b3521839a5d958714bd8ad2efc2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 21 Oct 2018 23:38:20 +0100 Subject: [PATCH 041/197] fix non osx builds --- src/Avalonia.Native/Avalonia.Native.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 8407a1b3f6..33463e27f6 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -21,7 +21,7 @@ - + runtimes/osx/native/libAvaloniaNative.dylib true From a13b170ca5d1801fc00111d254d4d82b315b3481 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 22 Oct 2018 10:13:51 +0100 Subject: [PATCH 042/197] print environment vars. --- azure-pipelines.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 64334d991a..7a54f397bd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,6 +11,7 @@ jobs: - script: | dotnet --info + printenv ./build.sh --target "Azure-Linux" --configuration "Release" - job: macOS @@ -32,6 +33,7 @@ jobs: - script: | dotnet --info + printenv ./build.sh --target "Azure-OSX" --configuration "Release" - job: Windows From c18001b69ddc5aa4e62201b136c312ee47e42f74 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 22 Oct 2018 20:58:17 +0300 Subject: [PATCH 043/197] Introduce Version for writable bitmaps --- src/Avalonia.Visuals/Platform/IBitmapImpl.cs | 5 +++++ .../Rendering/SceneGraph/ImageNode.cs | 9 ++++++-- src/Skia/Avalonia.Skia/ImmutableBitmap.cs | 2 ++ src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs | 5 ++++- src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs | 22 ++++++++++++++----- .../Media/Imaging/BitmapImpl.cs | 1 + .../Imaging/D2DRenderTargetBitmapImpl.cs | 2 +- .../Imaging/WicRenderTargetBitmapImpl.cs | 6 ++++- .../Media/Imaging/WriteableWicBitmapImpl.cs | 8 +++++-- 9 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Visuals/Platform/IBitmapImpl.cs b/src/Avalonia.Visuals/Platform/IBitmapImpl.cs index d60838452e..6d19205b8f 100644 --- a/src/Avalonia.Visuals/Platform/IBitmapImpl.cs +++ b/src/Avalonia.Visuals/Platform/IBitmapImpl.cs @@ -20,6 +20,11 @@ namespace Avalonia.Platform /// Gets the height of the bitmap, in pixels. /// int PixelHeight { get; } + + /// + /// Version of the pixel data + /// + int Version { get; } /// /// Saves the bitmap to a file. diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 1abd966a9f..e1bdcaab3b 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -30,6 +30,7 @@ namespace Avalonia.Rendering.SceneGraph SourceRect = sourceRect; DestRect = destRect; BitmapInterpolationMode = bitmapInterpolationMode; + SourceVersion = Source.Item.Version; } /// @@ -42,6 +43,11 @@ namespace Avalonia.Rendering.SceneGraph /// public IRef Source { get; } + /// + /// Source bitmap Version + /// + public int SourceVersion { get; } + /// /// Gets the draw opacity. /// @@ -83,6 +89,7 @@ namespace Avalonia.Rendering.SceneGraph { return transform == Transform && Equals(source.Item, Source.Item) && + source.Item.Version == SourceVersion && opacity == Opacity && sourceRect == SourceRect && destRect == DestRect && @@ -92,8 +99,6 @@ namespace Avalonia.Rendering.SceneGraph /// public override void Render(IDrawingContextImpl context) { - // TODO: Probably need to introduce some kind of locking mechanism in the case of - // WriteableBitmap. context.Transform = Transform; context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode); } diff --git a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs index 332b8547bf..9eb443caa3 100644 --- a/src/Skia/Avalonia.Skia/ImmutableBitmap.cs +++ b/src/Skia/Avalonia.Skia/ImmutableBitmap.cs @@ -65,6 +65,8 @@ namespace Avalonia.Skia /// public int PixelHeight { get; } + public int Version { get; } = 1; + /// public void Dispose() { diff --git a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs index 914dc7d05a..a1e9f1d31e 100644 --- a/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Reactive.Disposables; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Skia.Helpers; @@ -79,7 +80,7 @@ namespace Avalonia.Skia GrContext = _grContext }; - return new DrawingContextImpl(createInfo); + return new DrawingContextImpl(createInfo, Disposable.Create(() => Version++)); } /// @@ -88,6 +89,8 @@ namespace Avalonia.Skia /// public int PixelHeight { get; } + public int Version { get; private set; } = 1; + /// public void Save(string fileName) { diff --git a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs index 915aa77b52..8ad454461c 100644 --- a/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/WriteableBitmapImpl.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Threading; using Avalonia.Platform; using Avalonia.Skia.Helpers; using SkiaSharp; @@ -16,6 +17,7 @@ namespace Avalonia.Skia { private static readonly SKBitmapReleaseDelegate s_releaseDelegate = ReleaseProc; private readonly SKBitmap _bitmap; + private readonly object _lock = new object(); /// /// Create new writeable bitmap. @@ -55,10 +57,13 @@ namespace Avalonia.Skia /// public int PixelHeight { get; } + public int Version { get; private set; } = 1; + /// public void Draw(DrawingContextImpl context, SKRect sourceRect, SKRect destRect, SKPaint paint) { - context.Canvas.DrawBitmap(_bitmap, sourceRect, destRect, paint); + lock (_lock) + context.Canvas.DrawBitmap(_bitmap, sourceRect, destRect, paint); } /// @@ -86,7 +91,7 @@ namespace Avalonia.Skia } /// - public ILockedFramebuffer Lock() => new BitmapFramebuffer(_bitmap); + public ILockedFramebuffer Lock() => new BitmapFramebuffer(this, _bitmap); /// /// Get snapshot as image. @@ -94,7 +99,8 @@ namespace Avalonia.Skia /// Image snapshot. public SKImage GetSnapshot() { - return SKImage.FromPixels(_bitmap.Info, _bitmap.GetPixels(), _bitmap.RowBytes); + lock (_lock) + return SKImage.FromPixels(_bitmap.Info, _bitmap.GetPixels(), _bitmap.RowBytes); } /// @@ -112,22 +118,28 @@ namespace Avalonia.Skia /// private class BitmapFramebuffer : ILockedFramebuffer { + private WriteableBitmapImpl _parent; private SKBitmap _bitmap; /// /// Create framebuffer from given bitmap. /// /// Bitmap. - public BitmapFramebuffer(SKBitmap bitmap) + public BitmapFramebuffer(WriteableBitmapImpl parent, SKBitmap bitmap) { + _parent = parent; _bitmap = bitmap; + Monitor.Enter(parent._lock); } /// public void Dispose() { _bitmap.NotifyPixelsChanged(); + _parent.Version++; + Monitor.Exit(_parent._lock); _bitmap = null; + _parent = null; } /// @@ -149,4 +161,4 @@ namespace Avalonia.Skia public PixelFormat Format => _bitmap.ColorType.ToPixelFormat(); } } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs index 30af01283a..265f6f205a 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs @@ -9,6 +9,7 @@ namespace Avalonia.Direct2D1.Media { public abstract int PixelWidth { get; } public abstract int PixelHeight { get; } + public int Version { get; protected set; } = 1; public abstract OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target); diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs index 3646d9e9e1..bb43256657 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs @@ -35,7 +35,7 @@ namespace Avalonia.Direct2D1.Media.Imaging public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) { - return new DrawingContextImpl(visualBrushRenderer, this, _renderTarget); + return new DrawingContextImpl(visualBrushRenderer, this, _renderTarget, null, () => Version++); } public IRenderTargetBitmapImpl CreateLayer(Size size) diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs index aa8b3ead42..d620266086 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs @@ -44,7 +44,11 @@ namespace Avalonia.Direct2D1.Media public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer, Action finishedCallback) { - return new DrawingContextImpl(visualBrushRenderer, null, _renderTarget, finishedCallback: finishedCallback); + return new DrawingContextImpl(visualBrushRenderer, null, _renderTarget, finishedCallback: () => + { + Version++; + finishedCallback?.Invoke(); + }); } } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs index 5ca78ef278..7930266f75 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs @@ -17,11 +17,13 @@ namespace Avalonia.Direct2D1.Media.Imaging class LockedBitmap : ILockedFramebuffer { + private readonly WriteableWicBitmapImpl _parent; private readonly BitmapLock _lock; private readonly PixelFormat _format; - public LockedBitmap(BitmapLock l, PixelFormat format) + public LockedBitmap(WriteableWicBitmapImpl parent, BitmapLock l, PixelFormat format) { + _parent = parent; _lock = l; _format = format; } @@ -30,6 +32,7 @@ namespace Avalonia.Direct2D1.Media.Imaging public void Dispose() { _lock.Dispose(); + _parent.Version++; } public IntPtr Address => _lock.Data.DataPointer; @@ -41,6 +44,7 @@ namespace Avalonia.Direct2D1.Media.Imaging } - public ILockedFramebuffer Lock() => new LockedBitmap(WicImpl.Lock(BitmapLockFlags.Write), PixelFormat.Value); + public ILockedFramebuffer Lock() => + new LockedBitmap(this, WicImpl.Lock(BitmapLockFlags.Write), PixelFormat.Value); } } From 3aabd354ade22470f6c233e92ef77f668ae0f676 Mon Sep 17 00:00:00 2001 From: artyom Date: Tue, 23 Oct 2018 00:29:29 +0300 Subject: [PATCH 044/197] Use activation behavior like on other XAML platforms --- src/Avalonia.ReactiveUI/ReactiveUserControl.cs | 1 - src/Avalonia.ReactiveUI/ReactiveWindow.cs | 1 - .../AvaloniaActivationForViewFetcherTest.cs | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs index 5df6399c38..04c6f100a6 100644 --- a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs +++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs @@ -24,7 +24,6 @@ namespace Avalonia public ReactiveUserControl() { DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; - this.WhenActivated(disposables => { /* activate ViewModel */ }); } /// diff --git a/src/Avalonia.ReactiveUI/ReactiveWindow.cs b/src/Avalonia.ReactiveUI/ReactiveWindow.cs index c8b0c59d67..bb50a37764 100644 --- a/src/Avalonia.ReactiveUI/ReactiveWindow.cs +++ b/src/Avalonia.ReactiveUI/ReactiveWindow.cs @@ -24,7 +24,6 @@ namespace Avalonia public ReactiveWindow() { DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; - this.WhenActivated(disposables => { /* activate ViewModel */ }); } /// diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs index cdf19c067d..b782311729 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs @@ -70,12 +70,12 @@ namespace Avalonia public class ActivatableWindow : ReactiveWindow { - public ActivatableWindow() { } + public ActivatableWindow() => this.WhenActivated(disposables => { }); } public class ActivatableUserControl : ReactiveUserControl { - public ActivatableUserControl() { } + public ActivatableUserControl() => this.WhenActivated(disposables => { }); } public AvaloniaActivationForViewFetcherTest() From 156945b011ff5bb53eb2c164df3f45a0d689eec4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 22 Oct 2018 22:47:51 +0100 Subject: [PATCH 045/197] Azure compatible version numbering --- build.cake | 1 + build/SharedVersion.props | 4 ++-- parameters.cake | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 5273bce302..baa157cc9f 100644 --- a/build.cake +++ b/build.cake @@ -70,6 +70,7 @@ Setup(context => Information("IsRunningOnUnix: " + parameters.IsRunningOnUnix); Information("IsRunningOnWindows: " + parameters.IsRunningOnWindows); Information("IsRunningOnAppVeyor: " + parameters.IsRunningOnAppVeyor); + Information("IsRunnongOnAzure:" + parameters.IsRunningOnAzure); Information("IsPullRequest: " + parameters.IsPullRequest); Information("IsMainRepo: " + parameters.IsMainRepo); Information("IsMasterBranch: " + parameters.IsMasterBranch); diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 351583a106..6ca65014b1 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -2,8 +2,8 @@ xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> Avalonia - 0.6.2 - Copyright 2016 © The AvaloniaUI Project + 0.7.0 + Copyright 2018 © The AvaloniaUI Project https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md https://github.com/AvaloniaUI/Avalonia/ https://github.com/AvaloniaUI/Avalonia/ diff --git a/parameters.cake b/parameters.cake index 814c96da45..eea3e282cb 100644 --- a/parameters.cake +++ b/parameters.cake @@ -14,6 +14,7 @@ public class Parameters public bool IsRunningOnUnix { get; private set; } public bool IsRunningOnWindows { get; private set; } public bool IsRunningOnAppVeyor { get; private set; } + public bool IsRunningOnAzure { get; private set; } public bool IsPullRequest { get; private set; } public bool IsMainRepo { get; private set; } public bool IsMasterBranch { get; private set; } @@ -53,6 +54,8 @@ public class Parameters IsRunningOnUnix = context.IsRunningOnUnix(); IsRunningOnWindows = context.IsRunningOnWindows(); IsRunningOnAppVeyor = buildSystem.AppVeyor.IsRunningOnAppVeyor; + IsRunningOnAzure = buildSystem.IsRunningOnTFS; + IsPullRequest = buildSystem.AppVeyor.Environment.PullRequest.IsPullRequest; IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, buildSystem.AppVeyor.Environment.Repository.Name); IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, buildSystem.AppVeyor.Environment.Repository.Branch); @@ -85,6 +88,11 @@ public class Parameters Version += "-build" + context.EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-beta"; } } + else if (IsRunningOnAzure) + { + // Use AssemblyVersion with Build as version + Version += "-build" + context.EnvironmentVariable("BUILD_BUILDID") + "-beta"; + } // DIRECTORIES ArtifactsDir = (DirectoryPath)context.Directory("./artifacts"); From 616eff2c080c7df368851bb9ad807139a61c1c03 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 22 Oct 2018 22:54:01 +0100 Subject: [PATCH 046/197] fix IsRunningOnAzure --- parameters.cake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parameters.cake b/parameters.cake index eea3e282cb..c4ab4adb5c 100644 --- a/parameters.cake +++ b/parameters.cake @@ -54,7 +54,7 @@ public class Parameters IsRunningOnUnix = context.IsRunningOnUnix(); IsRunningOnWindows = context.IsRunningOnWindows(); IsRunningOnAppVeyor = buildSystem.AppVeyor.IsRunningOnAppVeyor; - IsRunningOnAzure = buildSystem.IsRunningOnTFS; + IsRunningOnAzure = buildSystem.IsRunningOnVSTS; IsPullRequest = buildSystem.AppVeyor.Environment.PullRequest.IsPullRequest; IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, buildSystem.AppVeyor.Environment.Repository.Name); From c1dd44ead4cf42d13bb36b4ef74b1caa52a4c35e Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Sun, 21 Oct 2018 23:48:43 +0300 Subject: [PATCH 047/197] unit test for issue #2000 button with render transform don't trigger click --- .../ButtonTests.cs | 165 +++++++++++++++++- 1 file changed, 163 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs index d218960726..9c9d09d4f8 100644 --- a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs @@ -1,7 +1,10 @@ using System; using System.Windows.Input; using Avalonia.Data; -using Avalonia.Markup.Data; +using Avalonia.Input; +using Avalonia.Media; +using Avalonia.VisualTree; +using Moq; using Xunit; namespace Avalonia.Controls.UnitTests @@ -92,6 +95,164 @@ namespace Avalonia.Controls.UnitTests Assert.False(target.IsEnabled); } + [Fact] + public void Button_Is_Raising_Click() + { + var mouse = Mock.Of(); + IInputElement captured = null; + Mock.Get(mouse).Setup(m => m.GetPosition(It.IsAny())).Returns(new Point(50, 50)); + Mock.Get(mouse).Setup(m => m.Capture(It.IsAny())).Callback(v => captured = v); + Mock.Get(mouse).Setup(m => m.Captured).Returns(() => captured); + + var target = new TestButton() { Bounds = new Rect(0, 0, 100, 100) }; + + bool clicked = false; + + target.Click += (s, e) => clicked = true; + + RaisePointerEnter(target, mouse); + RaisePointerMove(target, mouse); + RaisePointerPressed(target, mouse, 1, MouseButton.Left); + + Assert.Equal(captured, target); + + RaisePointerReleased(target, mouse, MouseButton.Left); + + Assert.Equal(captured, null); + + Assert.True(clicked); + } + + [Fact] + public void Button_Is_Not_Raising_Click_When_PointerReleased_Outside() + { + var mouse = Mock.Of(); + IInputElement captured = null; + Mock.Get(mouse).Setup(m => m.GetPosition(It.IsAny())).Returns(new Point(200, 50)); + Mock.Get(mouse).Setup(m => m.Capture(It.IsAny())).Callback(v => captured = v); + Mock.Get(mouse).Setup(m => m.Captured).Returns(() => captured); + + var target = new TestButton() { Bounds = new Rect(0, 0, 100, 100) }; + + bool clicked = false; + + target.Click += (s, e) => clicked = true; + + RaisePointerEnter(target, mouse); + RaisePointerMove(target, mouse); + RaisePointerPressed(target, mouse, 1, MouseButton.Left); + RaisePointerLeave(target, mouse); + + Assert.Equal(captured, target); + + RaisePointerReleased(target, mouse, MouseButton.Left); + + Assert.Equal(captured, null); + + Assert.False(clicked); + } + + [Fact] + public void Button_With_RenderTransform_Is_Raising_Click() + { + var mouse = Mock.Of(); + IInputElement captured = null; + Mock.Get(mouse).Setup(m => m.GetPosition(It.IsAny())).Returns(new Point(150, 50)); + Mock.Get(mouse).Setup(m => m.Capture(It.IsAny())).Callback(v => captured = v); + Mock.Get(mouse).Setup(m => m.Captured).Returns(() => captured); + + var target = new TestButton() + { + Bounds = new Rect(0, 0, 100, 100), + RenderTransform = new TranslateTransform { X = 100, Y = 0 } + }; + + //actual bounds of button should be 100,0,100,100 x -> translated 100 pixels + //so mouse with x=150 coordinates should trigger click + //button shouldn't count on bounds to calculate pointer is in the over or not, but + //on avalonia event system, as renderer hit test will properly calculate whether to send + //mouse over events to button based on rendered bounds + //note: button also may have not rectangular shape and only renderer hit testing is reliable + + bool clicked = false; + + target.Click += (s, e) => clicked = true; + + RaisePointerEnter(target, mouse); + RaisePointerMove(target, mouse); + RaisePointerPressed(target, mouse, 1, MouseButton.Left); + + Assert.Equal(captured, target); + + RaisePointerReleased(target, mouse, MouseButton.Left); + + Assert.Equal(captured, null); + + Assert.True(clicked); + } + + private class TestButton : Button + { + public new Rect Bounds + { + get => base.Bounds; + set => base.Bounds = value; + } + } + + private void RaisePointerPressed(Button button, IMouseDevice device, int clickCount, MouseButton mouseButton) + { + button.RaiseEvent(new PointerPressedEventArgs + { + RoutedEvent = InputElement.PointerPressedEvent, + Source = button, + MouseButton = mouseButton, + ClickCount = clickCount, + Device = device, + }); + } + + private void RaisePointerReleased(Button button, IMouseDevice device, MouseButton mouseButton) + { + button.RaiseEvent(new PointerReleasedEventArgs + { + RoutedEvent = InputElement.PointerReleasedEvent, + Source = button, + MouseButton = mouseButton, + Device = device, + }); + } + + private void RaisePointerEnter(Button button, IMouseDevice device) + { + button.RaiseEvent(new PointerEventArgs + { + RoutedEvent = InputElement.PointerEnterEvent, + Source = button, + Device = device, + }); + } + + private void RaisePointerLeave(Button button, IMouseDevice device) + { + button.RaiseEvent(new PointerEventArgs + { + RoutedEvent = InputElement.PointerLeaveEvent, + Source = button, + Device = device, + }); + } + + private void RaisePointerMove(Button button, IMouseDevice device) + { + button.RaiseEvent(new PointerEventArgs + { + RoutedEvent = InputElement.PointerMovedEvent, + Source = button, + Device = device, + }); + } + private class TestCommand : ICommand { private bool _enabled; @@ -123,4 +284,4 @@ namespace Avalonia.Controls.UnitTests } } } -} \ No newline at end of file +} From e1874b4a4c442f0cda18ffe9e02d1304d783913b Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 23 Oct 2018 01:13:04 +0300 Subject: [PATCH 048/197] fix for issue #2000 button with rendertransform don't fire click --- src/Avalonia.Controls/Button.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 24b2af7996..9c4c33f549 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -251,7 +251,9 @@ namespace Avalonia.Controls IsPressed = false; e.Handled = true; - if (ClickMode == ClickMode.Release && new Rect(Bounds.Size).Contains(e.GetPosition(this))) + //only renderer (hittesting) know better whether pointer is over the bounds of the button + if (ClickMode == ClickMode.Release && + (IsPointerOver || new Rect(Bounds.Size).Contains(e.GetPosition(this)))) { OnClick(); } From a600fb52ae17e05ae97f311396d0ad715fb08662 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Sun, 21 Oct 2018 18:42:35 +0300 Subject: [PATCH 049/197] unit test for invalidate on immediate renderer when renderedtransfom is used, issue #1998 --- .../Rendering/ImmediateRendererTests.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs new file mode 100644 index 0000000000..1fff36f8ff --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Avalonia.Media; +using Avalonia.Rendering; +using Avalonia.VisualTree; +using Moq; +using Xunit; + +namespace Avalonia.Visuals.UnitTests.Rendering +{ + public class ImmediateRendererTests + { + [Fact] + public void AddDirty_Call_RenderRoot_Invalidate() + { + var visual = new Mock(); + var child = new Mock(); + var renderRoot = visual.As(); + + visual.As().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400)); + + child.As().Setup(v => v.Bounds).Returns(new Rect(10, 10, 100, 100)); + child.As().Setup(v => v.VisualParent).Returns(visual.Object); + child.As().Setup(v => v.RenderTransform).Returns(default(Transform)); + child.As().Setup(v => v.RenderTransformOrigin).Returns(new RelativePoint(0.5, 0.5, RelativeUnit.Relative)); + child.As().Setup(v => v.TransformToVisual(It.IsAny())).CallBase(); + + var target = new ImmediateRenderer(visual.Object); + + target.AddDirty(child.Object); + + renderRoot.Verify(v => v.Invalidate(new Rect(10, 10, 100, 100))); + } + + + [Fact] + public void AddDirty_With_RenderTransform_Call_RenderRoot_Invalidate() + { + var visual = new Mock(); + var child = new Mock(); + var renderRoot = visual.As(); + + visual.As().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400)); + + child.As().Setup(v => v.Bounds).Returns(new Rect(100, 100, 100, 100)); + child.As().Setup(v => v.VisualParent).Returns(visual.Object); + child.As().Setup(v => v.RenderTransform).Returns(new ScaleTransform() { ScaleX = 2, ScaleY = 2 }); + child.As().Setup(v => v.RenderTransformOrigin).Returns(new RelativePoint(0.5, 0.5, RelativeUnit.Relative)); + child.As().Setup(v => v.TransformToVisual(It.IsAny())).CallBase(); + + var target = new ImmediateRenderer(visual.Object); + + target.AddDirty(child.Object); + + renderRoot.Verify(v => v.Invalidate(new Rect(50, 50, 200, 200))); + } + + + public class TestVisual : Visual + { + public new Rect Bounds + { + get => base.Bounds; + set => base.Bounds = value; + } + } + } +} From 645eadd55cb30d51760a90959972099004b86ccc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 22 Oct 2018 23:19:48 +0100 Subject: [PATCH 050/197] publish binaries as artifacts to allow packaging in second stage. --- azure-pipelines.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7a54f397bd..48fa77ba39 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,6 +13,10 @@ jobs: dotnet --info printenv ./build.sh --target "Azure-Linux" --configuration "Release" + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: '$(Build.SourcesDirectory)/artifacts/bin' + artifactName: 'BinariesLinux' - job: macOS pool: @@ -35,6 +39,15 @@ jobs: dotnet --info printenv ./build.sh --target "Azure-OSX" --configuration "Release" + + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: '$(Build.SourcesDirectory)/Build/Products/Release/' + artifactName: 'Avalonia.Native.OSX' + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: '$(Build.SourcesDirectory)/artifacts/bin' + artifactName: 'BinariesOSX' - job: Windows pool: @@ -52,3 +65,7 @@ jobs: inputs: pathToPublish: '$(Build.SourcesDirectory)/artifacts/zip' artifactName: 'Samples' + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: '$(Build.SourcesDirectory)/artifacts/bin' + artifactName: 'BinariesWindows' From 7fd6975658b6fe82deb7f461174480d4b6642753 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 23 Oct 2018 01:19:16 +0300 Subject: [PATCH 051/197] fix ImmediateRenderer invalidation for controls with RenderTransform issue #1998 --- .../Rendering/ImmediateRenderer.cs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index d373e7ef2a..96512b41a1 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -115,12 +115,45 @@ namespace Avalonia.Rendering } } + private static Matrix? TransformToVisual(IVisual visual, IVisual root) + { + var result = Matrix.Identity; + + while (visual != root) + { + if (visual.RenderTransform?.Value != null) + { + var origin = visual.RenderTransformOrigin.ToPixels(visual.Bounds.Size); + var offset = Matrix.CreateTranslation(origin); + var renderTransform = (-offset) * visual.RenderTransform.Value * (offset); + + result *= renderTransform; + } + + var topLeft = visual.Bounds.TopLeft; + + if (topLeft != default) + { + result *= Matrix.CreateTranslation(topLeft); + } + + visual = visual.VisualParent; + + if (visual == null) + { + return null; + } + } + + return result; + } + /// public void AddDirty(IVisual visual) { if (visual.Bounds != Rect.Empty) { - var m = visual.TransformToVisual(_root); + var m = TransformToVisual(visual, _root); if (m.HasValue) { @@ -191,7 +224,7 @@ namespace Avalonia.Rendering } } - static IEnumerable HitTest( + private static IEnumerable HitTest( IVisual visual, Point p, Func filter) From 520085c60baaa7f853e25ea44d1504eedb7f02a5 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 22 Oct 2018 23:27:47 +0100 Subject: [PATCH 052/197] copy and zip bin files. --- build.cake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index baa157cc9f..41c9c30e13 100644 --- a/build.cake +++ b/build.cake @@ -339,10 +339,14 @@ Task("Travis") .IsDependentOn("Run-Tests"); Task("Azure-Linux") - .IsDependentOn("Run-Tests"); + .IsDependentOn("Run-Tests") + .IsDependentOn("Copy-Files-Impl") + .IsDependentOn("Zip-Files-Impl"); Task("Azure-OSX") - .IsDependentOn("Run-Tests"); + .IsDependentOn("Run-Tests") + .IsDependentOn("Copy-Files-Impl") + .IsDependentOn("Zip-Files-Impl"); Task("Azure-Windows") .IsDependentOn("Package") From 5ce71be598691be6b34caaee56076096f1bded52 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 23 Oct 2018 14:00:30 +0300 Subject: [PATCH 053/197] another failing unit test for invalidate on immediate renderer when renderedtransfom is used, issue #1998 --- .../Rendering/ImmediateRendererTests.cs | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs index 1fff36f8ff..41e1691f28 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/ImmediateRendererTests.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Collections.Generic; +using Avalonia.Collections; using Avalonia.Media; +using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.VisualTree; using Moq; @@ -33,7 +33,6 @@ namespace Avalonia.Visuals.UnitTests.Rendering renderRoot.Verify(v => v.Invalidate(new Rect(10, 10, 100, 100))); } - [Fact] public void AddDirty_With_RenderTransform_Call_RenderRoot_Invalidate() { @@ -56,6 +55,51 @@ namespace Avalonia.Visuals.UnitTests.Rendering renderRoot.Verify(v => v.Invalidate(new Rect(50, 50, 200, 200))); } + [Fact] + public void AddDirty_For_Child_Moved_Should_Invalidate_Previous_Bounds() + { + var visual = new Mock(); + var child = new Mock(); + var renderRoot = visual.As(); + var renderTarget = visual.As(); + + renderRoot.Setup(r => r.CreateRenderTarget()).Returns(renderTarget.Object); + renderTarget.Setup(r => r.CreateDrawingContext(It.IsAny())).Returns(Mock.Of()); + + visual.As().Setup(v => v.Bounds).Returns(new Rect(0, 0, 400, 400)); + visual.As().Setup(v => v.VisualChildren).Returns(new AvaloniaList() { child.As().Object }); + + Rect childBounds = new Rect(0, 0, 100, 100); + child.As().Setup(v => v.Bounds).Returns(() => childBounds); + child.As().Setup(v => v.VisualParent).Returns(visual.Object); + child.As().Setup(v => v.TransformToVisual(It.IsAny())).CallBase(); + child.As().Setup(v => v.VisualChildren).Returns(new AvaloniaList()); + + var invalidationCalls = new List(); + + renderRoot.Setup(v => v.Invalidate(It.IsAny())).Callback(v => invalidationCalls.Add(v)); + + var target = new ImmediateRenderer(visual.Object); + + target.AddDirty(child.Object); + + Assert.Equal(new Rect(0, 0, 100, 100), invalidationCalls[0]); + + target.Paint(new Rect(0, 0, 100, 100)); + + //move child 100 pixels bottom/right + childBounds = new Rect(100, 100, 100, 100); + + //renderer should invalidate old child bounds with new one + //as on old area there can be artifacts + target.AddDirty(child.Object); + + //invalidate first old position + Assert.Equal(new Rect(0, 0, 100, 100), invalidationCalls[1]); + + //then new position + Assert.Equal(new Rect(100, 100, 100, 100), invalidationCalls[2]); + } public class TestVisual : Visual { From bd86168fd1e2580774d95d7d83fe839bc06eaf45 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 12:05:19 +0100 Subject: [PATCH 054/197] dont publish linux binaries --- azure-pipelines.yml | 4 ---- build.cake | 4 +--- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 48fa77ba39..65e1a67123 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,10 +13,6 @@ jobs: dotnet --info printenv ./build.sh --target "Azure-Linux" --configuration "Release" - - task: PublishBuildArtifacts@1 - inputs: - pathToPublish: '$(Build.SourcesDirectory)/artifacts/bin' - artifactName: 'BinariesLinux' - job: macOS pool: diff --git a/build.cake b/build.cake index 41c9c30e13..49bf49e238 100644 --- a/build.cake +++ b/build.cake @@ -339,9 +339,7 @@ Task("Travis") .IsDependentOn("Run-Tests"); Task("Azure-Linux") - .IsDependentOn("Run-Tests") - .IsDependentOn("Copy-Files-Impl") - .IsDependentOn("Zip-Files-Impl"); + .IsDependentOn("Run-Tests"); Task("Azure-OSX") .IsDependentOn("Run-Tests") From 03384d3b5efea383f435e276efea055d83627680 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 23 Oct 2018 14:05:53 +0300 Subject: [PATCH 055/197] fix ImmediateRenderer invalidation for controls moved with RenderTransform issue #1998 --- src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 96512b41a1..e5e3533bf6 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -23,6 +23,7 @@ namespace Avalonia.Rendering private readonly IVisual _root; private readonly IRenderRoot _renderRoot; private IRenderTarget _renderTarget; + private Rect _lastPaintBounds; /// /// Initializes a new instance of the class. @@ -45,6 +46,8 @@ namespace Avalonia.Rendering /// public void Paint(Rect rect) { + _lastPaintBounds = rect; + if (_renderTarget == null) { _renderTarget = ((IRenderRoot)_root).CreateRenderTarget(); @@ -158,6 +161,13 @@ namespace Avalonia.Rendering if (m.HasValue) { var bounds = new Rect(visual.Bounds.Size).TransformToAABB(m.Value); + + if (_lastPaintBounds != default) + { + _renderRoot?.Invalidate(_lastPaintBounds); + _lastPaintBounds = default; + } + _renderRoot?.Invalidate(bounds); } } From 922917b29937ca0cc07e4a2d7d62c3bc5e0f8503 Mon Sep 17 00:00:00 2001 From: Andrey Kunchev Date: Tue, 23 Oct 2018 14:12:00 +0300 Subject: [PATCH 056/197] fix pr nits --- src/Avalonia.Controls/Button.cs | 1 - tests/Avalonia.Controls.UnitTests/ButtonTests.cs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index 9c4c33f549..0e8a765e57 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -251,7 +251,6 @@ namespace Avalonia.Controls IsPressed = false; e.Handled = true; - //only renderer (hittesting) know better whether pointer is over the bounds of the button if (ClickMode == ClickMode.Release && (IsPointerOver || new Rect(Bounds.Size).Contains(e.GetPosition(this)))) { diff --git a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs index 9c9d09d4f8..afc53f2fa9 100644 --- a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs @@ -96,7 +96,7 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Button_Is_Raising_Click() + public void Button_Raises_Click() { var mouse = Mock.Of(); IInputElement captured = null; @@ -124,7 +124,7 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Button_Is_Not_Raising_Click_When_PointerReleased_Outside() + public void Button_Does_Not_Raise_Click_When_PointerReleased_Outside() { var mouse = Mock.Of(); IInputElement captured = null; @@ -153,7 +153,7 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void Button_With_RenderTransform_Is_Raising_Click() + public void Button_With_RenderTransform_Raises_Click() { var mouse = Mock.Of(); IInputElement captured = null; From 0492989acb2abd1d311db8a1cb637eccc80ab84b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:11:43 +0100 Subject: [PATCH 057/197] use cake 0.30 --- azure-pipelines.yml | 24 ++++++++++++++++-------- build.cake | 1 - 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 65e1a67123..0f0ab0201b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,11 +8,14 @@ jobs: script: | sudo apt-get update sudo apt-get install castxml + - task: CmdLine@2 + inputs: + dotnet tool install -g Cake.Tool --version 0.30.0 - script: | dotnet --info printenv - ./build.sh --target "Azure-Linux" --configuration "Release" + dotnet cake build.cake -target="Azure-Linux" -configuration="Release" - job: macOS pool: @@ -26,15 +29,18 @@ jobs: configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcodeVersion: 'default' # Options: 8, 9, default, specifyPath - args: '-derivedDataPath ./' + args: '-derivedDataPath ./' - task: CmdLine@2 inputs: script: brew install castxml + - task: CmdLine@2 + inputs: + dotnet tool install -g Cake.Tool --version 0.30.0 - script: | dotnet --info - printenv - ./build.sh --target "Azure-OSX" --configuration "Release" + printenv + dotnet cake build.cake -target="Azure-OSX" -configuration="Release" - task: PublishBuildArtifacts@1 inputs: @@ -49,10 +55,12 @@ jobs: pool: vmImage: 'vs2017-win2016' steps: - - task: PowerShell@2 - inputs: - filePath: build.ps1 - arguments: -target "Azure-Windows" -configuration "Release" + - task: CmdLine@2 + inputs: + dotnet tool install -g Cake.Tool --version 0.30.0 + - task: CmdLine@2 + inputs: + dotnet cake build.cake -target="Azure-Windows" -configuration="Release" - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget' diff --git a/build.cake b/build.cake index 49bf49e238..e5a4e3470d 100644 --- a/build.cake +++ b/build.cake @@ -20,7 +20,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using NuGet; /////////////////////////////////////////////////////////////////////////////// // SCRIPTS From 41697121d3fc25e1f19dbc8c315f6a19fab65641 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:13:17 +0100 Subject: [PATCH 058/197] fix yaml --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f0ab0201b..d5f139bec2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,7 @@ jobs: sudo apt-get update sudo apt-get install castxml - task: CmdLine@2 - inputs: + inputs: dotnet tool install -g Cake.Tool --version 0.30.0 - script: | @@ -34,7 +34,7 @@ jobs: inputs: script: brew install castxml - task: CmdLine@2 - inputs: + inputs: dotnet tool install -g Cake.Tool --version 0.30.0 - script: | @@ -56,10 +56,10 @@ jobs: vmImage: 'vs2017-win2016' steps: - task: CmdLine@2 - inputs: + inputs: dotnet tool install -g Cake.Tool --version 0.30.0 - task: CmdLine@2 - inputs: + inputs: dotnet cake build.cake -target="Azure-Windows" -configuration="Release" - task: PublishBuildArtifacts@1 inputs: From 53ab6a296279da9a5e075139434b3d5504db2bdd Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:16:28 +0100 Subject: [PATCH 059/197] fix yaml --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d5f139bec2..fe996195ee 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,7 +10,7 @@ jobs: sudo apt-get install castxml - task: CmdLine@2 inputs: - dotnet tool install -g Cake.Tool --version 0.30.0 + script: dotnet tool install -g Cake.Tool --version 0.30.0 - script: | dotnet --info @@ -35,7 +35,7 @@ jobs: script: brew install castxml - task: CmdLine@2 inputs: - dotnet tool install -g Cake.Tool --version 0.30.0 + script: dotnet tool install -g Cake.Tool --version 0.30.0 - script: | dotnet --info @@ -57,10 +57,10 @@ jobs: steps: - task: CmdLine@2 inputs: - dotnet tool install -g Cake.Tool --version 0.30.0 + script: dotnet tool install -g Cake.Tool --version 0.30.0 - task: CmdLine@2 inputs: - dotnet cake build.cake -target="Azure-Windows" -configuration="Release" + script: dotnet cake build.cake -target="Azure-Windows" -configuration="Release" - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget' From 2cd8d4809e27dd750e71230befca8853d456d5be Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:22:09 +0100 Subject: [PATCH 060/197] set path to tools --- azure-pipelines.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fe996195ee..6936fcc9e1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,7 +10,9 @@ jobs: sudo apt-get install castxml - task: CmdLine@2 inputs: - script: dotnet tool install -g Cake.Tool --version 0.30.0 + script: | + dotnet tool install -g Cake.Tool --version 0.30.0 + export PATH="$PATH:$HOME/.dotnet/tools" - script: | dotnet --info @@ -35,7 +37,9 @@ jobs: script: brew install castxml - task: CmdLine@2 inputs: - script: dotnet tool install -g Cake.Tool --version 0.30.0 + script: | + dotnet tool install -g Cake.Tool --version 0.30.0 + export PATH="$PATH:$HOME/.dotnet/tools" - script: | dotnet --info @@ -57,7 +61,9 @@ jobs: steps: - task: CmdLine@2 inputs: - script: dotnet tool install -g Cake.Tool --version 0.30.0 + script: | + dotnet tool install -g Cake.Tool --version 0.30.0 + set PATH=%PATH%;%USERPROFILE%\.dotnet\tools - task: CmdLine@2 inputs: script: dotnet cake build.cake -target="Azure-Windows" -configuration="Release" From 3bb7e90bf5a6dcc14d86b9c4befa0335ae13c368 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:23:14 +0100 Subject: [PATCH 061/197] yaml!!! --- azure-pipelines.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6936fcc9e1..b04f7d6997 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -11,8 +11,8 @@ jobs: - task: CmdLine@2 inputs: script: | - dotnet tool install -g Cake.Tool --version 0.30.0 - export PATH="$PATH:$HOME/.dotnet/tools" + dotnet tool install -g Cake.Tool --version 0.30.0 + export PATH="$PATH:$HOME/.dotnet/tools" - script: | dotnet --info @@ -38,8 +38,8 @@ jobs: - task: CmdLine@2 inputs: script: | - dotnet tool install -g Cake.Tool --version 0.30.0 - export PATH="$PATH:$HOME/.dotnet/tools" + dotnet tool install -g Cake.Tool --version 0.30.0 + export PATH="$PATH:$HOME/.dotnet/tools" - script: | dotnet --info @@ -62,8 +62,8 @@ jobs: - task: CmdLine@2 inputs: script: | - dotnet tool install -g Cake.Tool --version 0.30.0 - set PATH=%PATH%;%USERPROFILE%\.dotnet\tools + dotnet tool install -g Cake.Tool --version 0.30.0 + set PATH=%PATH%;%USERPROFILE%\.dotnet\tools - task: CmdLine@2 inputs: script: dotnet cake build.cake -target="Azure-Windows" -configuration="Release" From 0d3a6dc0f8deb18202c92fa6022a347448856687 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:27:01 +0100 Subject: [PATCH 062/197] fix path to cake --- azure-pipelines.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b04f7d6997..67f4303f6a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,9 +12,9 @@ jobs: inputs: script: | dotnet tool install -g Cake.Tool --version 0.30.0 - export PATH="$PATH:$HOME/.dotnet/tools" - script: | + export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv dotnet cake build.cake -target="Azure-Linux" -configuration="Release" @@ -39,9 +39,8 @@ jobs: inputs: script: | dotnet tool install -g Cake.Tool --version 0.30.0 - export PATH="$PATH:$HOME/.dotnet/tools" - - script: | + export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv dotnet cake build.cake -target="Azure-OSX" -configuration="Release" @@ -63,10 +62,11 @@ jobs: inputs: script: | dotnet tool install -g Cake.Tool --version 0.30.0 - set PATH=%PATH%;%USERPROFILE%\.dotnet\tools - task: CmdLine@2 inputs: - script: dotnet cake build.cake -target="Azure-Windows" -configuration="Release" + script: | + set PATH=%PATH%;%USERPROFILE%\.dotnet\tools + dotnet cake build.cake -target="Azure-Windows" -configuration="Release" - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.SourcesDirectory)/artifacts/nuget' From 161ee7dafe3eb3aac1587e6397d3cb8a9e8f1095 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:32:11 +0100 Subject: [PATCH 063/197] fix dotnet initialization on osx --- azure-pipelines.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 67f4303f6a..872865a9e8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -40,6 +40,11 @@ jobs: script: | dotnet tool install -g Cake.Tool --version 0.30.0 - script: | + export COREHOST_TRACE=0 + export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + export DOTNET_CLI_TELEMETRY_OPTOUT=1 + which dotnet + dotnet --info export PATH="$PATH:$HOME/.dotnet/tools" dotnet --info printenv From 18ca29236a63274a9e4e7d342e645b8398b123f3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 13:56:40 +0100 Subject: [PATCH 064/197] manually install dotnet on osx --- azure-pipelines.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 872865a9e8..1eb7e226c8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,6 +23,9 @@ jobs: pool: vmImage: 'xcode9-macos10.13' steps: + - task: DotNetCoreInstaller@0 + inputs: + version: '2.1.403' - task: Xcode@5 inputs: actions: 'build' From 14ff4f4a33bd3c2e6ee95205bcd193896c7433a1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 23 Oct 2018 14:26:51 +0100 Subject: [PATCH 065/197] burn monomac and make ci build avalonia.native instead. --- Avalonia.sln | 39 +- build/MonoMac.props | 5 - packages.cake | 16 +- src/Avalonia.DotNetCoreRuntime/AppBuilder.cs | 4 +- .../Avalonia.DotNetCoreRuntime.csproj | 2 +- src/OSX/Avalonia.MonoMac/AssemblyInfo.cs | 6 - .../Avalonia.MonoMac/Avalonia.MonoMac.csproj | 20 - src/OSX/Avalonia.MonoMac/ClipboardImpl.cs | 29 - src/OSX/Avalonia.MonoMac/Cursor.cs | 66 --- src/OSX/Avalonia.MonoMac/DragSource.cs | 119 ----- src/OSX/Avalonia.MonoMac/DraggingInfo.cs | 89 --- .../Avalonia.MonoMac/EmulatedFramebuffer.cs | 106 ---- src/OSX/Avalonia.MonoMac/Helpers.cs | 40 -- src/OSX/Avalonia.MonoMac/KeyTransform.cs | 267 --------- src/OSX/Avalonia.MonoMac/MacScreen.cs | 25 - src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs | 140 ----- .../PlatformThreadingInterface.cs | 74 --- src/OSX/Avalonia.MonoMac/PopupImpl.cs | 30 -- src/OSX/Avalonia.MonoMac/RenderTimer.cs | 28 - src/OSX/Avalonia.MonoMac/ScreenImpl.cs | 49 -- src/OSX/Avalonia.MonoMac/Stubs.cs | 47 -- src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs | 89 --- src/OSX/Avalonia.MonoMac/TopLevelImpl.cs | 505 ------------------ src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs | 208 -------- src/OSX/Avalonia.MonoMac/WindowImpl.cs | 176 ------ 25 files changed, 9 insertions(+), 2170 deletions(-) delete mode 100644 build/MonoMac.props delete mode 100644 src/OSX/Avalonia.MonoMac/AssemblyInfo.cs delete mode 100644 src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj delete mode 100644 src/OSX/Avalonia.MonoMac/ClipboardImpl.cs delete mode 100644 src/OSX/Avalonia.MonoMac/Cursor.cs delete mode 100644 src/OSX/Avalonia.MonoMac/DragSource.cs delete mode 100644 src/OSX/Avalonia.MonoMac/DraggingInfo.cs delete mode 100644 src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs delete mode 100644 src/OSX/Avalonia.MonoMac/Helpers.cs delete mode 100644 src/OSX/Avalonia.MonoMac/KeyTransform.cs delete mode 100644 src/OSX/Avalonia.MonoMac/MacScreen.cs delete mode 100644 src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs delete mode 100644 src/OSX/Avalonia.MonoMac/PlatformThreadingInterface.cs delete mode 100644 src/OSX/Avalonia.MonoMac/PopupImpl.cs delete mode 100644 src/OSX/Avalonia.MonoMac/RenderTimer.cs delete mode 100644 src/OSX/Avalonia.MonoMac/ScreenImpl.cs delete mode 100644 src/OSX/Avalonia.MonoMac/Stubs.cs delete mode 100644 src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs delete mode 100644 src/OSX/Avalonia.MonoMac/TopLevelImpl.cs delete mode 100644 src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs delete mode 100644 src/OSX/Avalonia.MonoMac/WindowImpl.cs diff --git a/Avalonia.sln b/Avalonia.sln index 0883e051c1..a95007bdc6 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -80,13 +80,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-C EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.AndroidTestApplication", "src\Android\Avalonia.AndroidTestApplication\Avalonia.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.iOSTestApplication", "src\iOS\Avalonia.iOSTestApplication\Avalonia.iOSTestApplication.csproj", "{8C923867-8A8F-4F6B-8B80-47D9E8436166}" EndProject @@ -164,7 +164,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Direct3DInteropSample", "samples\interop\Direct3DInteropSample\Direct3DInteropSample.csproj", "{638580B0-7910-40EF-B674-DCB34DA308CD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}" EndProject @@ -178,17 +178,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Previewer", "samples\Previewer\Previewer.csproj", "{F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OSX", "OSX", "{A59C4C0A-64DF-4621-B450-2BA00D6F61E2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MonoMac", "src\OSX\Avalonia.MonoMac\Avalonia.MonoMac.csproj", "{CBFD5788-567D-401B-9DFA-74E4224025A0}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp.NetFX", "src\tools\Avalonia.Designer.HostApp.NetFX\Avalonia.Designer.HostApp.NetFX.csproj", "{4ADA61C8-D191-428D-9066-EF4F0D86520F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Native", "src\Avalonia.Native\Avalonia.Native.csproj", "{12A91A62-C064-42CA-9A8C-A1272F354388}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -1595,30 +1591,6 @@ Global {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.Build.0 = Release|Any CPU {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhone.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhone.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|Any CPU.Build.0 = Release|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhone.ActiveCfg = Release|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhone.Build.0 = Release|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CBFD5788-567D-401B-9DFA-74E4224025A0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {4ADA61C8-D191-428D-9066-EF4F0D86520F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU @@ -1765,7 +1737,6 @@ Global {E2999E4A-9086-401F-898C-AEB0AD38E676} = {9B9E3891-2366-4253-A952-D08BCEB71098} {050CC912-FF49-4A8B-B534-9544017446DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {CBFD5788-567D-401B-9DFA-74E4224025A0} = {A59C4C0A-64DF-4621-B450-2BA00D6F61E2} {4ADA61C8-D191-428D-9066-EF4F0D86520F} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {E1240B49-7B4B-4371-A00E-068778C5CF0B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} EndGlobalSection diff --git a/build/MonoMac.props b/build/MonoMac.props deleted file mode 100644 index 5cf19ef503..0000000000 --- a/build/MonoMac.props +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packages.cake b/packages.cake index fea45153f1..b2e6291662 100644 --- a/packages.cake +++ b/packages.cake @@ -408,20 +408,6 @@ public class Packages BasePath = context.Directory("./src/Skia/Avalonia.Skia/bin/" + parameters.DirSuffix + "/netstandard2.0"), OutputDirectory = parameters.NugetRoot }, - new NuGetPackSettings() - { - Id = "Avalonia.MonoMac", - Dependencies = new DependencyBuilder(this) - { - new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version } - }.Dep("MonoMac.NetStandard").ToArray(), - Files = new [] - { - new NuSpecContent { Source = "netstandard2.0/Avalonia.MonoMac.dll", Target = "lib/netstandard2.0" }, - }, - BasePath = context.Directory("./src/OSX/Avalonia.MonoMac/bin/" + parameters.DirSuffix), - OutputDirectory = parameters.NugetRoot - }, /////////////////////////////////////////////////////////////////////////////// // Avalonia.Desktop /////////////////////////////////////////////////////////////////////////////// @@ -434,7 +420,7 @@ public class Packages new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Skia", Version = parameters.Version }, new NuSpecDependency() { Id = "Avalonia.Gtk3", Version = parameters.Version }, - new NuSpecDependency() { Id = "Avalonia.MonoMac", Version = parameters.Version } + new NuSpecDependency() { Id = "Avalonia.Native", Version = parameters.Version } }, Files = new NuSpecContent[] { diff --git a/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs b/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs index 5f1e845134..87f8a8de8d 100644 --- a/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs +++ b/src/Avalonia.DotNetCoreRuntime/AppBuilder.cs @@ -43,7 +43,7 @@ namespace Avalonia if (os == OperatingSystemType.WinNT) LoadWin32(); else if(os==OperatingSystemType.OSX) - LoadMonoMac(); + LoadAvaloniaNative(); else LoadGtk3(); this.UseSkia(); @@ -51,7 +51,7 @@ namespace Avalonia return this; } - void LoadMonoMac() => this.UseMonoMac(); + void LoadAvaloniaNative() => this.UseAvaloniaNative(); void LoadWin32() => this.UseWin32(); void LoadGtk3() => this.UseGtk3(); } diff --git a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj index 0aed0a9717..8b18a7e9f4 100644 --- a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj +++ b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj @@ -8,8 +8,8 @@ - + diff --git a/src/OSX/Avalonia.MonoMac/AssemblyInfo.cs b/src/OSX/Avalonia.MonoMac/AssemblyInfo.cs deleted file mode 100644 index efabb7d118..0000000000 --- a/src/OSX/Avalonia.MonoMac/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text;using Avalonia.MonoMac; -using Avalonia.Platform; -[assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 1, "MonoMac", typeof(MonoMacPlatform), nameof(MonoMacPlatform.Initialize))] - diff --git a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj b/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj deleted file mode 100644 index e675b43389..0000000000 --- a/src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - netstandard2.0 - True - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/ClipboardImpl.cs b/src/OSX/Avalonia.MonoMac/ClipboardImpl.cs deleted file mode 100644 index 475083b469..0000000000 --- a/src/OSX/Avalonia.MonoMac/ClipboardImpl.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using Avalonia.Input.Platform; -using MonoMac.AppKit; - -namespace Avalonia.MonoMac -{ - class ClipboardImpl : IClipboard - { - public Task GetTextAsync() - { - return Task.FromResult(NSPasteboard.GeneralPasteboard.GetStringForType(NSPasteboard.NSStringType)); - } - - public Task SetTextAsync(string text) - { - NSPasteboard.GeneralPasteboard.ClearContents(); - if (text != null) - NSPasteboard.GeneralPasteboard.SetStringForType(text, NSPasteboard.NSStringType); - return Task.CompletedTask; - } - - public Task ClearAsync() - { - NSPasteboard.GeneralPasteboard.ClearContents(); - return Task.CompletedTask; - } - } -} - diff --git a/src/OSX/Avalonia.MonoMac/Cursor.cs b/src/OSX/Avalonia.MonoMac/Cursor.cs deleted file mode 100644 index fff2d92e63..0000000000 --- a/src/OSX/Avalonia.MonoMac/Cursor.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using Avalonia.Input; -using Avalonia.Platform; -using MonoMac.AppKit; - -namespace Avalonia.MonoMac -{ - class Cursor : IPlatformHandle - { - - public NSCursor Native { get; } - - public IntPtr Handle => Native.Handle; - - public string HandleDescriptor => "NSCursor"; - - public Cursor(NSCursor native) - { - Native = native; - } - } - - class CursorFactoryStub : IStandardCursorFactory - { - Dictionary _cache; - - public CursorFactoryStub() - { - //TODO: Load diagonal cursors from webkit - //See https://stackoverflow.com/q/10733228 - _cache = new Dictionary() - { - [StandardCursorType.Arrow] = NSCursor.ArrowCursor, - [StandardCursorType.AppStarting] = NSCursor.ArrowCursor, //TODO - [StandardCursorType.BottomLeftCorner] = NSCursor.CrosshairCursor, //TODO - [StandardCursorType.BottomRightCorner] = NSCursor.CrosshairCursor, //TODO - [StandardCursorType.BottomSize] = NSCursor.ResizeDownCursor, - [StandardCursorType.Cross] = NSCursor.CrosshairCursor, - [StandardCursorType.Hand] = NSCursor.PointingHandCursor, - [StandardCursorType.Help] = NSCursor.ContextualMenuCursor, - [StandardCursorType.Ibeam] = NSCursor.IBeamCursor, - [StandardCursorType.LeftSide] = NSCursor.ResizeLeftCursor, - [StandardCursorType.No] = NSCursor.OperationNotAllowedCursor, - [StandardCursorType.RightSide] = NSCursor.ResizeRightCursor, - [StandardCursorType.SizeAll] = NSCursor.CrosshairCursor, //TODO - [StandardCursorType.SizeNorthSouth] = NSCursor.ResizeUpDownCursor, - [StandardCursorType.SizeWestEast] = NSCursor.ResizeLeftRightCursor, - [StandardCursorType.TopLeftCorner] = NSCursor.CrosshairCursor, //TODO - [StandardCursorType.TopRightCorner] = NSCursor.CrosshairCursor, //TODO - [StandardCursorType.TopSide] = NSCursor.ResizeUpCursor, - [StandardCursorType.UpArrow] = NSCursor.ResizeUpCursor, - [StandardCursorType.Wait] = NSCursor.ArrowCursor, //TODO - [StandardCursorType.DragMove] = NSCursor.DragCopyCursor, // TODO - [StandardCursorType.DragCopy] = NSCursor.DragCopyCursor, - [StandardCursorType.DragLink] = NSCursor.DragLinkCursor, - - }; - } - - public IPlatformHandle GetCursor(StandardCursorType cursorType) - { - return new Cursor(_cache[cursorType]); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/DragSource.cs b/src/OSX/Avalonia.MonoMac/DragSource.cs deleted file mode 100644 index 5d799d3fbe..0000000000 --- a/src/OSX/Avalonia.MonoMac/DragSource.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Runtime.Serialization.Formatters.Binary; -using System.Threading.Tasks; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Input.Platform; -using Avalonia.Input.Raw; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; -using MonoMac.Foundation; - -namespace Avalonia.MonoMac -{ - public class DragSource : NSDraggingSource, IPlatformDragSource - { - private const string NSPasteboardTypeString = "public.utf8-plain-text"; - private const string NSPasteboardTypeFileUrl = "public.file-url"; - - private readonly Subject _result = new Subject(); - private readonly IInputManager _inputManager; - private DragDropEffects _allowedEffects; - - public override bool IgnoreModifierKeysWhileDragging => false; - - public DragSource() - { - _inputManager = AvaloniaLocator.Current.GetService(); - } - - private string DataFormatToUTI(string s) - { - if (s == DataFormats.FileNames) - return NSPasteboardTypeFileUrl; - if (s == DataFormats.Text) - return NSPasteboardTypeString; - return s; - } - - private NSDraggingItem CreateDraggingItem(string format, object data) - { - var pasteboardItem = new NSPasteboardItem(); - NSData nsData; - if (data is string s) - { - if (format == DataFormats.FileNames) - s = new Uri(s).AbsoluteUri; // Ensure file uris... - nsData = NSData.FromString(s); - } - else if (data is Stream strm) - nsData = NSData.FromStream(strm); - else if (data is byte[] bytes) - nsData = NSData.FromArray(bytes); - else - { - BinaryFormatter bf = new BinaryFormatter(); - using (var ms = new MemoryStream()) - { - bf.Serialize(ms, data); - ms.Position = 0; - nsData = NSData.FromStream(ms); - } - } - pasteboardItem.SetDataForType(nsData, DataFormatToUTI(format)); - - NSPasteboardWriting writing = new NSPasteboardWriting(pasteboardItem.Handle); - - return new NSDraggingItem(writing); - } - - public IEnumerable CreateDraggingItems(string format, object data) - { - if (format == DataFormats.FileNames && data is IEnumerable files) - { - foreach (var file in files) - yield return CreateDraggingItem(format, file); - - yield break; - } - - yield return CreateDraggingItem(format, data); - } - - - public async Task DoDragDrop(IDataObject data, DragDropEffects allowedEffects) - { - // We need the TopLevelImpl + a mouse location so we just wait for the next event. - var mouseEv = await _inputManager.PreProcess.OfType().FirstAsync(); - var view = ((mouseEv.Root as TopLevel)?.PlatformImpl as TopLevelImpl)?.View; - if (view == null) - return DragDropEffects.None; - - // Prepare the source event: - var pt = view.TranslateLocalPoint(mouseEv.Position).ToMonoMacPoint(); - var ev = NSEvent.MouseEvent(NSEventType.LeftMouseDown, pt, 0, 0, 0, null, 0, 0, 0); - - _allowedEffects = allowedEffects; - var items = data.GetDataFormats().SelectMany(fmt => CreateDraggingItems(fmt, data.Get(fmt))).ToArray(); - view.BeginDraggingSession(items ,ev, this); - - return await _result; - } - - public override NSDragOperation DraggingSourceOperationMaskForLocal(bool flag) - { - return DraggingInfo.ConvertDragOperation(_allowedEffects); - } - - public override void DraggedImageEndedAtOperation(NSImage image, CGPoint screenPoint, NSDragOperation operation) - { - _result.OnNext(DraggingInfo.ConvertDragOperation(operation)); - _result.OnCompleted(); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/DraggingInfo.cs b/src/OSX/Avalonia.MonoMac/DraggingInfo.cs deleted file mode 100644 index 5ea7169a1e..0000000000 --- a/src/OSX/Avalonia.MonoMac/DraggingInfo.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Avalonia.Input; -using MonoMac.AppKit; -using MonoMac.Foundation; - -namespace Avalonia.MonoMac -{ - class DraggingInfo : IDataObject - { - private readonly NSDraggingInfo _info; - - public DraggingInfo(NSDraggingInfo info) - { - _info = info; - } - - internal static NSDragOperation ConvertDragOperation(DragDropEffects d) - { - NSDragOperation result = NSDragOperation.None; - if (d.HasFlag(DragDropEffects.Copy)) - result |= NSDragOperation.Copy; - if (d.HasFlag(DragDropEffects.Link)) - result |= NSDragOperation.Link; - if (d.HasFlag(DragDropEffects.Move)) - result |= NSDragOperation.Move; - return result; - } - - internal static DragDropEffects ConvertDragOperation(NSDragOperation d) - { - DragDropEffects result = DragDropEffects.None; - if (d.HasFlag(NSDragOperation.Copy)) - result |= DragDropEffects.Copy; - if (d.HasFlag(NSDragOperation.Link)) - result |= DragDropEffects.Link; - if (d.HasFlag(NSDragOperation.Move)) - result |= DragDropEffects.Move; - return result; - } - - public Point Location => new Point(_info.DraggingLocation.X, _info.DraggingLocation.Y); - - public IEnumerable GetDataFormats() - { - return _info.DraggingPasteboard.Types.Select(NSTypeToWellknownType); - } - - private string NSTypeToWellknownType(string type) - { - if (type == NSPasteboard.NSStringType) - return DataFormats.Text; - if (type == NSPasteboard.NSFilenamesType) - return DataFormats.FileNames; - return type; - } - - public string GetText() - { - return _info.DraggingPasteboard.GetStringForType(NSPasteboard.NSStringType); - } - - public IEnumerable GetFileNames() - { - using(var fileNames = (NSArray)_info.DraggingPasteboard.GetPropertyListForType(NSPasteboard.NSFilenamesType)) - { - if (fileNames != null) - return NSArray.StringArrayFromHandle(fileNames.Handle); - } - - return Enumerable.Empty(); - } - - public bool Contains(string dataFormat) - { - return GetDataFormats().Any(f => f == dataFormat); - } - - public object Get(string dataFormat) - { - if (dataFormat == DataFormats.Text) - return GetText(); - if (dataFormat == DataFormats.FileNames) - return GetFileNames(); - - return _info.DraggingPasteboard.GetDataForType(dataFormat).ToArray(); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs b/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs deleted file mode 100644 index 4da67ae1dd..0000000000 --- a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Avalonia.Platform; -using Avalonia.Threading; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; - -namespace Avalonia.MonoMac -{ - class EmulatedFramebuffer : ILockedFramebuffer - { - private readonly TopLevelImpl.TopLevelView _view; - private readonly CGSize _logicalSize; - private readonly bool _isDeferred; - private readonly IUnmanagedBlob _blob; - - [DllImport("libc")] - static extern void memset(IntPtr p, int c, IntPtr size); - - public EmulatedFramebuffer(TopLevelImpl.TopLevelView view) - { - _view = view; - - _isDeferred = !Dispatcher.UIThread.CheckAccess(); - _logicalSize = _view.LogicalSize; - var pixelSize = _view.PixelSize; - Width = (int)pixelSize.Width; - Height = (int)pixelSize.Height; - RowBytes = Width * 4; - Dpi = new Vector(96 * pixelSize.Width / _logicalSize.Width, 96 * pixelSize.Height / _logicalSize.Height); - Format = PixelFormat.Rgba8888; - var size = Height * RowBytes; - _blob = AvaloniaLocator.Current.GetService().AllocBlob(size); - memset(Address, 0, new IntPtr(size)); - } - - public void Dispose() - { - if (_blob.IsDisposed) - return; - var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast; - CGImage image = null; - try - { - using (var colorSpace = CGColorSpace.CreateDeviceRGB()) - using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, - colorSpace, (CGImageAlphaInfo)nfo)) - image = bContext.ToImage(); - lock (_view.SyncRoot) - { - if(!_isDeferred) - { - using (var nscontext = NSGraphicsContext.CurrentContext) - using (var context = nscontext.GraphicsPort) - { - context.SetFillColor(255, 255, 255, 255); - context.FillRect(new CGRect(default(CGPoint), _view.LogicalSize)); - context.TranslateCTM(0, _view.LogicalSize.Height - _logicalSize.Height); - context.DrawImage(new CGRect(default(CGPoint), _logicalSize), image); - context.Flush(); - nscontext.FlushGraphics(); - } - } - } - } - finally - { - if (image != null) - { - if (!_isDeferred) - image.Dispose(); - else - _view.SetBackBufferImage(new SavedImage(image, _logicalSize)); - } - _blob.Dispose(); - } - - - } - - public IntPtr Address => _blob.Address; - public int Width { get; } - public int Height { get; } - public int RowBytes { get; } - public Vector Dpi { get; } - public PixelFormat Format { get; } - } - - class SavedImage : IDisposable - { - public CGImage Image { get; private set; } - public CGSize LogicalSize { get; } - - public SavedImage(CGImage image, CGSize logicalSize) - { - Image = image; - LogicalSize = logicalSize; - } - - public void Dispose() - { - Image?.Dispose(); - Image = null; - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/Helpers.cs b/src/OSX/Avalonia.MonoMac/Helpers.cs deleted file mode 100644 index 527eccafdc..0000000000 --- a/src/OSX/Avalonia.MonoMac/Helpers.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; - -namespace Avalonia.MonoMac -{ - static class Helpers - { - public static Point ToAvaloniaPoint(this CGPoint point) => new Point(point.X, point.Y); - public static CGPoint ToMonoMacPoint(this Point point) => new CGPoint(point.X, point.Y); - public static Size ToAvaloniaSize(this CGSize size) => new Size(size.Width, size.Height); - public static CGSize ToMonoMacSize(this Size size) => new CGSize(size.Width, size.Height); - public static Rect ToAvaloniaRect(this CGRect rect) => new Rect(rect.Left, rect.Top, rect.Width, rect.Height); - public static CGRect ToMonoMacRect(this Rect rect) => new CGRect(rect.X, rect.Y, rect.Width, rect.Height); - - public static Point ConvertPointY(this Point pt) - { - var sw = NSScreen.Screens[0].Frame; - var t = Math.Max(sw.Top, sw.Bottom); - return pt.WithY(t - pt.Y); - } - - public static CGPoint ConvertPointY(this CGPoint pt) - { - var sw = NSScreen.Screens[0].Frame; - var t = Math.Max(sw.Top, sw.Bottom); - return new CGPoint(pt.X, t - pt.Y); - } - - public static Rect ConvertRectY(this Rect rect) - { - return new Rect(rect.Position.WithY(rect.Y + rect.Height).ConvertPointY(), rect.Size); - } - - public static CGRect ConvertRectY(this CGRect rect) - { - return new CGRect(new CGPoint(rect.X, rect.Y + rect.Height).ConvertPointY(), rect.Size); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/KeyTransform.cs b/src/OSX/Avalonia.MonoMac/KeyTransform.cs deleted file mode 100644 index 4abd5a24f1..0000000000 --- a/src/OSX/Avalonia.MonoMac/KeyTransform.cs +++ /dev/null @@ -1,267 +0,0 @@ -using System.Collections.Generic; -using Avalonia.Input; - -namespace Avalonia.MonoMac -{ - public static class KeyTransform - { - // See /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h - // ReSharper disable InconsistentNaming - // ReSharper disable UnusedMember.Local - private const int kVK_ANSI_A = 0x00; - private const int kVK_ANSI_S = 0x01; - private const int kVK_ANSI_D = 0x02; - private const int kVK_ANSI_F = 0x03; - private const int kVK_ANSI_H = 0x04; - private const int kVK_ANSI_G = 0x05; - private const int kVK_ANSI_Z = 0x06; - private const int kVK_ANSI_X = 0x07; - private const int kVK_ANSI_C = 0x08; - private const int kVK_ANSI_V = 0x09; - private const int kVK_ANSI_B = 0x0B; - private const int kVK_ANSI_Q = 0x0C; - private const int kVK_ANSI_W = 0x0D; - private const int kVK_ANSI_E = 0x0E; - private const int kVK_ANSI_R = 0x0F; - private const int kVK_ANSI_Y = 0x10; - private const int kVK_ANSI_T = 0x11; - private const int kVK_ANSI_1 = 0x12; - private const int kVK_ANSI_2 = 0x13; - private const int kVK_ANSI_3 = 0x14; - private const int kVK_ANSI_4 = 0x15; - private const int kVK_ANSI_6 = 0x16; - private const int kVK_ANSI_5 = 0x17; - private const int kVK_ANSI_Equal = 0x18; - private const int kVK_ANSI_9 = 0x19; - private const int kVK_ANSI_7 = 0x1A; - private const int kVK_ANSI_Minus = 0x1B; - private const int kVK_ANSI_8 = 0x1C; - private const int kVK_ANSI_0 = 0x1D; - private const int kVK_ANSI_RightBracket = 0x1E; - private const int kVK_ANSI_O = 0x1F; - private const int kVK_ANSI_U = 0x20; - private const int kVK_ANSI_LeftBracket = 0x21; - private const int kVK_ANSI_I = 0x22; - private const int kVK_ANSI_P = 0x23; - private const int kVK_ANSI_L = 0x25; - private const int kVK_ANSI_J = 0x26; - private const int kVK_ANSI_Quote = 0x27; - private const int kVK_ANSI_K = 0x28; - private const int kVK_ANSI_Semicolon = 0x29; - private const int kVK_ANSI_Backslash = 0x2A; - private const int kVK_ANSI_Comma = 0x2B; - private const int kVK_ANSI_Slash = 0x2C; - private const int kVK_ANSI_N = 0x2D; - private const int kVK_ANSI_M = 0x2E; - private const int kVK_ANSI_Period = 0x2F; - private const int kVK_ANSI_Grave = 0x32; - private const int kVK_ANSI_KeypadDecimal = 0x41; - private const int kVK_ANSI_KeypadMultiply = 0x43; - private const int kVK_ANSI_KeypadPlus = 0x45; - private const int kVK_ANSI_KeypadClear = 0x47; - private const int kVK_ANSI_KeypadDivide = 0x4B; - private const int kVK_ANSI_KeypadEnter = 0x4C; - private const int kVK_ANSI_KeypadMinus = 0x4E; - private const int kVK_ANSI_KeypadEquals = 0x51; - private const int kVK_ANSI_Keypad0 = 0x52; - private const int kVK_ANSI_Keypad1 = 0x53; - private const int kVK_ANSI_Keypad2 = 0x54; - private const int kVK_ANSI_Keypad3 = 0x55; - private const int kVK_ANSI_Keypad4 = 0x56; - private const int kVK_ANSI_Keypad5 = 0x57; - private const int kVK_ANSI_Keypad6 = 0x58; - private const int kVK_ANSI_Keypad7 = 0x59; - private const int kVK_ANSI_Keypad8 = 0x5B; - private const int kVK_ANSI_Keypad9 = 0x5C; - private const int kVK_Return = 0x24; - private const int kVK_Tab = 0x30; - private const int kVK_Space = 0x31; - private const int kVK_Delete = 0x33; - private const int kVK_Escape = 0x35; - private const int kVK_Command = 0x37; - private const int kVK_Shift = 0x38; - private const int kVK_CapsLock = 0x39; - private const int kVK_Option = 0x3A; - private const int kVK_Control = 0x3B; - private const int kVK_RightCommand = 0x36; - private const int kVK_RightShift = 0x3C; - private const int kVK_RightOption = 0x3D; - private const int kVK_RightControl = 0x3E; - private const int kVK_Function = 0x3F; - private const int kVK_F17 = 0x40; - private const int kVK_VolumeUp = 0x48; - private const int kVK_VolumeDown = 0x49; - private const int kVK_Mute = 0x4A; - private const int kVK_F18 = 0x4F; - private const int kVK_F19 = 0x50; - private const int kVK_F20 = 0x5A; - private const int kVK_F5 = 0x60; - private const int kVK_F6 = 0x61; - private const int kVK_F7 = 0x62; - private const int kVK_F3 = 0x63; - private const int kVK_F8 = 0x64; - private const int kVK_F9 = 0x65; - private const int kVK_F11 = 0x67; - private const int kVK_F13 = 0x69; - private const int kVK_F16 = 0x6A; - private const int kVK_F14 = 0x6B; - private const int kVK_F10 = 0x6D; - private const int kVK_F12 = 0x6F; - private const int kVK_F15 = 0x71; - private const int kVK_Help = 0x72; - private const int kVK_Home = 0x73; - private const int kVK_PageUp = 0x74; - private const int kVK_ForwardDelete = 0x75; - private const int kVK_F4 = 0x76; - private const int kVK_End = 0x77; - private const int kVK_F2 = 0x78; - private const int kVK_PageDown = 0x79; - private const int kVK_F1 = 0x7A; - private const int kVK_LeftArrow = 0x7B; - private const int kVK_RightArrow = 0x7C; - private const int kVK_DownArrow = 0x7D; - private const int kVK_UpArrow = 0x7E; - private const int kVK_ISO_Section = 0x0A; - private const int kVK_JIS_Yen = 0x5D; - private const int kVK_JIS_Underscore = 0x5E; - private const int kVK_JIS_KeypadComma = 0x5F; - private const int kVK_JIS_Eisu = 0x66; - private const int kVK_JIS_Kana = 0x68; - // ReSharper restore UnusedMember.Local - // ReSharper restore InconsistentNaming - //TODO: Map missing keys - static readonly Dictionary Keys = new Dictionary - { - [kVK_ANSI_A] = Key.A, - [kVK_ANSI_S] = Key.S, - [kVK_ANSI_D] = Key.D, - [kVK_ANSI_F] = Key.F, - [kVK_ANSI_H] = Key.H, - [kVK_ANSI_G] = Key.G, - [kVK_ANSI_Z] = Key.Z, - [kVK_ANSI_X] = Key.X, - [kVK_ANSI_C] = Key.C, - [kVK_ANSI_V] = Key.V, - [kVK_ANSI_B] = Key.B, - [kVK_ANSI_Q] = Key.Q, - [kVK_ANSI_W] = Key.W, - [kVK_ANSI_E] = Key.E, - [kVK_ANSI_R] = Key.R, - [kVK_ANSI_Y] = Key.Y, - [kVK_ANSI_T] = Key.T, - [kVK_ANSI_1] = Key.D1, - [kVK_ANSI_2] = Key.D2, - [kVK_ANSI_3] = Key.D3, - [kVK_ANSI_4] = Key.D4, - [kVK_ANSI_6] = Key.D6, - [kVK_ANSI_5] = Key.D5, - //[kVK_ANSI_Equal] = Key.?, - [kVK_ANSI_9] = Key.D9, - [kVK_ANSI_7] = Key.D7, - [kVK_ANSI_Minus] = Key.OemMinus, - [kVK_ANSI_8] = Key.D8, - [kVK_ANSI_0] = Key.D0, - [kVK_ANSI_RightBracket] = Key.OemCloseBrackets, - [kVK_ANSI_O] = Key.O, - [kVK_ANSI_U] = Key.U, - [kVK_ANSI_LeftBracket] = Key.OemOpenBrackets, - [kVK_ANSI_I] = Key.I, - [kVK_ANSI_P] = Key.P, - [kVK_ANSI_L] = Key.L, - [kVK_ANSI_J] = Key.J, - [kVK_ANSI_Quote] = Key.OemQuotes, - [kVK_ANSI_K] = Key.K, - [kVK_ANSI_Semicolon] = Key.OemSemicolon, - [kVK_ANSI_Backslash] = Key.OemBackslash, - [kVK_ANSI_Comma] = Key.OemComma, - //[kVK_ANSI_Slash] = Key.?, - [kVK_ANSI_N] = Key.N, - [kVK_ANSI_M] = Key.M, - [kVK_ANSI_Period] = Key.OemPeriod, - //[kVK_ANSI_Grave] = Key.?, - [kVK_ANSI_KeypadDecimal] = Key.Decimal, - [kVK_ANSI_KeypadMultiply] = Key.Multiply, - [kVK_ANSI_KeypadPlus] = Key.OemPlus, - [kVK_ANSI_KeypadClear] = Key.Clear, - [kVK_ANSI_KeypadDivide] = Key.Divide, - [kVK_ANSI_KeypadEnter] = Key.Enter, - [kVK_ANSI_KeypadMinus] = Key.OemMinus, - //[kVK_ANSI_KeypadEquals] = Key.?, - [kVK_ANSI_Keypad0] = Key.NumPad0, - [kVK_ANSI_Keypad1] = Key.NumPad1, - [kVK_ANSI_Keypad2] = Key.NumPad2, - [kVK_ANSI_Keypad3] = Key.NumPad3, - [kVK_ANSI_Keypad4] = Key.NumPad4, - [kVK_ANSI_Keypad5] = Key.NumPad5, - [kVK_ANSI_Keypad6] = Key.NumPad6, - [kVK_ANSI_Keypad7] = Key.NumPad7, - [kVK_ANSI_Keypad8] = Key.NumPad8, - [kVK_ANSI_Keypad9] = Key.NumPad9, - [kVK_Return] = Key.Return, - [kVK_Tab] = Key.Tab, - [kVK_Space] = Key.Space, - [kVK_Delete] = Key.Back, - [kVK_Escape] = Key.Escape, - [kVK_Command] = Key.LWin, - [kVK_Shift] = Key.LeftShift, - [kVK_CapsLock] = Key.CapsLock, - [kVK_Option] = Key.LeftAlt, - [kVK_Control] = Key.LeftCtrl, - [kVK_RightCommand] = Key.RWin, - [kVK_RightShift] = Key.RightShift, - [kVK_RightOption] = Key.RightAlt, - [kVK_RightControl] = Key.RightCtrl, - //[kVK_Function] = Key.?, - [kVK_F17] = Key.F17, - [kVK_VolumeUp] = Key.VolumeUp, - [kVK_VolumeDown] = Key.VolumeDown, - [kVK_Mute] = Key.VolumeMute, - [kVK_F18] = Key.F18, - [kVK_F19] = Key.F19, - [kVK_F20] = Key.F20, - [kVK_F5] = Key.F5, - [kVK_F6] = Key.F6, - [kVK_F7] = Key.F7, - [kVK_F3] = Key.F3, - [kVK_F8] = Key.F8, - [kVK_F9] = Key.F9, - [kVK_F11] = Key.F11, - [kVK_F13] = Key.F13, - [kVK_F16] = Key.F16, - [kVK_F14] = Key.F14, - [kVK_F10] = Key.F10, - [kVK_F12] = Key.F12, - [kVK_F15] = Key.F15, - [kVK_Help] = Key.Help, - [kVK_Home] = Key.Home, - [kVK_PageUp] = Key.PageUp, - [kVK_ForwardDelete] = Key.Delete, - [kVK_F4] = Key.F4, - [kVK_End] = Key.End, - [kVK_F2] = Key.F2, - [kVK_PageDown] = Key.PageDown, - [kVK_F1] = Key.F1, - [kVK_LeftArrow] = Key.Left, - [kVK_RightArrow] = Key.Right, - [kVK_DownArrow] = Key.Down, - [kVK_UpArrow] = Key.Up, - /* - [kVK_ISO_Section] = Key.?, - [kVK_JIS_Yen] = Key.?, - [kVK_JIS_Underscore] = Key.?, - [kVK_JIS_KeypadComma] = Key.?, - [kVK_JIS_Eisu] = Key.?, - [kVK_JIS_Kana] = Key.? - */ - }; - - - public static Key? TransformKeyCode(ushort code) - { - Key rv; - if (Keys.TryGetValue(code, out rv)) - return rv; - return null; - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/MacScreen.cs b/src/OSX/Avalonia.MonoMac/MacScreen.cs deleted file mode 100644 index 3d5ab0769f..0000000000 --- a/src/OSX/Avalonia.MonoMac/MacScreen.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Avalonia.Platform; - -namespace Avalonia.MonoMac -{ - public class MacScreen : Screen - { - private readonly IntPtr handle; - - public MacScreen(Rect bounds, Rect workingArea, bool primary, IntPtr handle) : base(bounds, workingArea, primary) - { - this.handle = handle; - } - - public override int GetHashCode() - { - return (int)handle; - } - - public override bool Equals(object obj) - { - return (obj is MacScreen screen) ? this.handle == screen.handle : base.Equals(obj); - } - } -} \ No newline at end of file diff --git a/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs b/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs deleted file mode 100644 index 0d2d4d3f9c..0000000000 --- a/src/OSX/Avalonia.MonoMac/MonoMacPlatform.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Threading; -using Avalonia.Controls; -using Avalonia.Controls.Platform; -using Avalonia.Input; -using Avalonia.Input.Platform; -using Avalonia.Platform; -using Avalonia.Rendering; -using MonoMac.AppKit; -using MonoMac.Foundation; -using MonoMac.ObjCRuntime; - -namespace Avalonia.MonoMac -{ - public class MonoMacPlatform : IWindowingPlatform, IPlatformSettings - { - internal static MonoMacPlatform Instance { get; private set; } - internal readonly MouseDevice MouseDevice = new MouseDevice(); - readonly KeyboardDevice _keyboardDevice = new KeyboardDevice(); - internal static NSApplication App; - private static bool s_monoMacInitialized; - private static bool s_showInDock = true; - private static IRenderLoop s_renderLoop; - private static IRenderTimer s_renderTimer; - - void DoInitialize() - { - InitializeMonoMac(); - AvaloniaLocator.CurrentMutable - .Bind().ToTransient() - .Bind().ToSingleton() - .Bind().ToConstant(_keyboardDevice) - .Bind().ToConstant(MouseDevice) - .Bind().ToConstant(this) - .Bind().ToConstant(this) - .Bind().ToSingleton() - .Bind().ToSingleton() - .Bind().ToConstant(s_renderLoop) - .Bind().ToConstant(s_renderTimer) - .Bind().ToConstant(new PlatformHotkeyConfiguration(InputModifiers.Windows)) - .Bind().ToConstant(PlatformThreadingInterface.Instance) - /*.Bind().ToTransient()*/; - } - - public static void Initialize() - { - Instance = new MonoMacPlatform(); - Instance.DoInitialize(); - - } - - - /// - /// See "Using POSIX Threads in a Cocoa Application" section here: - /// https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/20000738-125024 - /// - class ThreadHelper : NSObject - { - private readonly AutoResetEvent _event = new AutoResetEvent(false); - private const string InitThreadingName = "initThreading"; - [Export(InitThreadingName)] - public void DoNothing() - { - _event.Set(); - } - - public static void InitializeCocoaThreadingLocks() - { - var helper = new ThreadHelper(); - var thread = new NSThread(helper, Selector.FromHandle(Selector.GetHandle(InitThreadingName)), new NSObject()); - thread.Start(); - helper._event.WaitOne(); - helper._event.Dispose(); - if (!NSThread.IsMultiThreaded) - { - throw new Exception("Unable to initialize Cocoa threading"); - } - } - } - - void InitializeMonoMac() - { - if(s_monoMacInitialized) - return; - NSApplication.Init(); - ThreadHelper.InitializeCocoaThreadingLocks(); - App = NSApplication.SharedApplication; - UpdateActivationPolicy(); - s_renderLoop = new RenderLoop(); - s_renderTimer = new RenderTimer(60); //TODO: use CVDisplayLink - s_monoMacInitialized = true; - } - - static void UpdateActivationPolicy() => App.ActivationPolicy = ShowInDock - ? NSApplicationActivationPolicy.Regular - : NSApplicationActivationPolicy.Accessory; - - public static bool ShowInDock - { - get => s_showInDock; - set - { - s_showInDock = value; - if (s_monoMacInitialized) - UpdateActivationPolicy(); - } - } - - public static bool UseDeferredRendering { get; set; } = true; - - public Size DoubleClickSize => new Size(4, 4); - public TimeSpan DoubleClickTime => TimeSpan.FromSeconds(NSEvent.DoubleClickInterval); - - public IWindowImpl CreateWindow() => new WindowImpl(); - - public IEmbeddableWindowImpl CreateEmbeddableWindow() - { - throw new PlatformNotSupportedException(); - } - - public IPopupImpl CreatePopup() - { - return new PopupImpl(); - } - } -} - - -namespace Avalonia -{ - public static class MonoMacPlatformExtensions - { - public static T UseMonoMac(this T builder, bool? useDeferredRendering = null) where T : AppBuilderBase, new() - { - if (useDeferredRendering.HasValue) - MonoMac.MonoMacPlatform.UseDeferredRendering = useDeferredRendering.Value; - return builder.UseWindowingSubsystem(MonoMac.MonoMacPlatform.Initialize, "MonoMac"); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/PlatformThreadingInterface.cs b/src/OSX/Avalonia.MonoMac/PlatformThreadingInterface.cs deleted file mode 100644 index 04a36d9f0f..0000000000 --- a/src/OSX/Avalonia.MonoMac/PlatformThreadingInterface.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Threading; -using Avalonia.Platform; -using Avalonia.Threading; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; -using MonoMac.Foundation; -using MonoMac.ObjCRuntime; - -namespace Avalonia.MonoMac -{ - class PlatformThreadingInterface : NSObject, IPlatformThreadingInterface - { - private bool _signaled; - private const string SignaledSelectorName = "avaloniauiSignaled"; - private readonly Selector _signaledSelector = new Selector(SignaledSelectorName); - public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface(); - public bool CurrentThreadIsLoopThread => NSThread.Current.IsMainThread; - - public event Action Signaled; - - public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) - => NSTimer.CreateRepeatingScheduledTimer(interval, () => tick()); - - public void Signal(DispatcherPriority prio) - { - lock (this) - { - if (_signaled) - return; - _signaled = true; - } - PerformSelector(_signaledSelector, NSThread.MainThread, this, false, - new[] - { - NSRunLoop.NSDefaultRunLoopMode, NSRunLoop.NSRunLoopEventTracking, NSRunLoop.NSRunLoopModalPanelMode, - NSRunLoop.NSRunLoopCommonModes, NSRunLoop.NSRunLoopConnectionReplyMode - }); - } - - [Export(SignaledSelectorName)] - public void CallSignaled() - { - lock (this) - { - if (!_signaled) - return; - _signaled = false; - } - Signaled?.Invoke(null); - } - - - public void RunLoop(CancellationToken cancellationToken) - { - NSApplication.SharedApplication.ActivateIgnoringOtherApps(true); - var app = NSApplication.SharedApplication; - cancellationToken.Register(() => - { - app.PostEvent(NSEvent.OtherEvent(NSEventType.ApplicationDefined, default(CGPoint), - default(NSEventModifierMask), 0, 0, null, 0, 0, 0), true); - }); - while (!cancellationToken.IsCancellationRequested) - { - var ev = app.NextEvent(NSEventMask.AnyEvent, NSDate.DistantFuture, NSRunLoop.NSDefaultRunLoopMode, true); - if (ev != null) - { - app.SendEvent(ev); - ev.Dispose(); - } - } - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/PopupImpl.cs b/src/OSX/Avalonia.MonoMac/PopupImpl.cs deleted file mode 100644 index 267e47a6a0..0000000000 --- a/src/OSX/Avalonia.MonoMac/PopupImpl.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Avalonia.Platform; -using MonoMac.AppKit; - -namespace Avalonia.MonoMac -{ - class PopupImpl : WindowBaseImpl, IPopupImpl - { - public PopupImpl() - { - UpdateStyle(); - Window.Level = NSWindowLevel.PopUpMenu; - } - - protected override NSWindowStyle GetStyle() - { - return NSWindowStyle.Borderless; - } - - protected override CustomWindow CreateCustomWindow() => new CustomPopupWindow(this); - - private class CustomPopupWindow : CustomWindow - { - public CustomPopupWindow(WindowBaseImpl impl) - : base(impl) - { } - - public override bool WorksWhenModal() => true; - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/RenderTimer.cs b/src/OSX/Avalonia.MonoMac/RenderTimer.cs deleted file mode 100644 index f3c49828d6..0000000000 --- a/src/OSX/Avalonia.MonoMac/RenderTimer.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Avalonia.Platform; -using Avalonia.Rendering; -using MonoMac.Foundation; - -namespace Avalonia.MonoMac -{ - //TODO: Switch to using CVDisplayLink - public class RenderTimer : DefaultRenderTimer - { - public RenderTimer(int framesPerSecond) : base(framesPerSecond) - { - } - - protected override IDisposable StartCore(Action tick) - { - return AvaloniaLocator.Current.GetService().StartSystemTimer( - TimeSpan.FromSeconds(1.0 / FramesPerSecond), - () => - { - using (new NSAutoreleasePool()) - { - tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount)); - } - }); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/ScreenImpl.cs b/src/OSX/Avalonia.MonoMac/ScreenImpl.cs deleted file mode 100644 index 46cd200cab..0000000000 --- a/src/OSX/Avalonia.MonoMac/ScreenImpl.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Avalonia.Platform; -using MonoMac.AppKit; -using MonoMac.Foundation; - -namespace Avalonia.MonoMac -{ - public class ScreenImpl : IScreenImpl - { - private const string NSApplicationDidChangeScreenParametersNotification = "NSApplicationDidChangeScreenParametersNotification"; - - public int ScreenCount - { - get => NSScreen.Screens.Length; - } - - private Screen[] _allScreens; - public Screen[] AllScreens - { - get - { - if (_allScreens == null) - { - NSScreen[] screens = NSScreen.Screens; - Screen[] s = new Screen[screens.Length]; - NSScreen primary = NSScreen.MainScreen; - for (int i = 0; i < screens.Length; i++) - { - Rect bounds = screens[i].Frame.ToAvaloniaRect().ConvertRectY(); - Rect workArea = screens[i].VisibleFrame.ToAvaloniaRect().ConvertRectY(); - s[i] = new MacScreen(bounds, workArea, i == 0, screens[i].Handle); - } - - _allScreens = s; - } - return _allScreens; - } - } - - public ScreenImpl() - { - NSNotificationCenter.DefaultCenter.AddObserver(NSApplicationDidChangeScreenParametersNotification, MonitorsChanged); - } - - private void MonitorsChanged(NSNotification notification) - { - _allScreens = null; - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/Stubs.cs b/src/OSX/Avalonia.MonoMac/Stubs.cs deleted file mode 100644 index 188ceeaab1..0000000000 --- a/src/OSX/Avalonia.MonoMac/Stubs.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.IO; -using Avalonia.Platform; - -namespace Avalonia.MonoMac -{ - // OSX doesn't have a concept of *window* icon. - // Icons in the title bar are only shown if there is - // an opened file (on disk) associated with the current window - // see http://stackoverflow.com/a/7038671/2231814 - class IconLoader : IPlatformIconLoader - { - class IconStub : IWindowIconImpl - { - private readonly IBitmapImpl _bitmap; - - public IconStub(IBitmapImpl bitmap) - { - _bitmap = bitmap; - } - - public void Save(Stream outputStream) - { - _bitmap.Save(outputStream); - } - } - - public IWindowIconImpl LoadIcon(string fileName) - { - return new IconStub( - AvaloniaLocator.Current.GetService().LoadBitmap(fileName)); - } - - public IWindowIconImpl LoadIcon(Stream stream) - { - return new IconStub( - AvaloniaLocator.Current.GetService().LoadBitmap(stream)); - } - - public IWindowIconImpl LoadIcon(IBitmapImpl bitmap) - { - var ms = new MemoryStream(); - bitmap.Save(ms); - ms.Seek(0, SeekOrigin.Begin); - return LoadIcon(ms); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs b/src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs deleted file mode 100644 index 382311e28a..0000000000 --- a/src/OSX/Avalonia.MonoMac/SystemDialogsImpl.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using Avalonia.Controls; -using Avalonia.Controls.Platform; -using Avalonia.Platform; -using MonoMac.AppKit; -using MonoMac.Foundation; - -namespace Avalonia.MonoMac -{ - class SystemDialogsImpl : ISystemDialogImpl - { - - Task RunPanel(NSSavePanel panel, IWindowImpl parent) - { - var keyWindow = MonoMacPlatform.App.KeyWindow; - var tcs = new TaskCompletionSource(); - void OnComplete(int result) - { - if (result == 0) - tcs.SetResult(null); - else - { - if (panel is NSOpenPanel openPanel) - tcs.SetResult(openPanel.Urls.Select(url => url.AbsoluteString.Replace("file://", "")).ToArray()); - else - tcs.SetResult(new[] { panel.Url.AbsoluteString.Replace("file://", "") }); - } - panel.OrderOut(panel); - keyWindow?.MakeKeyAndOrderFront(keyWindow); - MonoMacPlatform.App.ActivateIgnoringOtherApps(true); - panel.Dispose(); - } - - if (parent != null) - { - var window = (WindowImpl)parent; - panel.BeginSheet(window.Window, OnComplete); - } - else - panel.Begin(OnComplete); - return tcs.Task; - } - - public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) - { - /* NOTES - * DefaultFileExtension is not supported - * Named filters are not supported - */ - NSSavePanel panel; - if (dialog is OpenFileDialog openDialog) - { - var openPanel = new NSOpenPanel(); - panel = openPanel; - - openPanel.AllowsMultipleSelection = openDialog.AllowMultiple; - } - else - panel = new NSSavePanel(); - panel.Title = panel.Title; - if (dialog.InitialDirectory != null) - panel.DirectoryUrl = new NSUrl(dialog.InitialDirectory); - if (dialog.InitialFileName != null) - panel.NameFieldStringValue = dialog.InitialFileName; - if (dialog.Filters?.Count > 0) - panel.AllowedFileTypes = dialog.Filters.SelectMany(f => f.Extensions).Distinct().ToArray(); - - - return RunPanel(panel, parent); - } - - - - public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) - { - var panel = new NSOpenPanel - { - Title = dialog.Title, - CanChooseDirectories = true, - CanCreateDirectories = true, - CanChooseFiles = false - }; - if (dialog.DefaultDirectory != null) - panel.DirectoryUrl = new NSUrl(dialog.DefaultDirectory); - return (await RunPanel(panel, parent))?.FirstOrDefault(); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs deleted file mode 100644 index fb4c5afc2d..0000000000 --- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs +++ /dev/null @@ -1,505 +0,0 @@ -using System; -using System.Collections.Generic; -using Avalonia.Controls.Platform.Surfaces; -using Avalonia.Input; -using Avalonia.Input.Raw; -using Avalonia.Platform; -using Avalonia.Rendering; -using Avalonia.Threading; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; -using MonoMac.Foundation; -using MonoMac.ObjCRuntime; - -namespace Avalonia.MonoMac -{ - abstract class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface - { - public TopLevelView View { get; } - private readonly IMouseDevice _mouse = AvaloniaLocator.Current.GetService(); - private readonly IDragDropDevice _dragDevice = AvaloniaLocator.Current.GetService(); - protected TopLevelImpl() - { - View = new TopLevelView(this); - } - - protected virtual void OnInput(RawInputEventArgs args) - { - Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); - Input?.Invoke(args); - } - - [Adopts("NSTextInputClient")] - public class TopLevelView : NSView - { - TopLevelImpl _tl; - bool _isLeftPressed, _isRightPressed, _isMiddlePressed; - private readonly IMouseDevice _mouse; - private readonly IKeyboardDevice _keyboard; - private NSTrackingArea _area; - private NSCursor _cursor; - private bool _nonUiRedrawQueued; - private bool _isMouseOver; - - public CGSize PixelSize { get; set; } - - public CGSize LogicalSize { get; set; } - - private SavedImage _backBuffer; - public object SyncRoot { get; } = new object(); - - public TopLevelView(TopLevelImpl tl) - { - _tl = tl; - _mouse = AvaloniaLocator.Current.GetService(); - _keyboard = AvaloniaLocator.Current.GetService(); - - RegisterForDraggedTypes(new string[] { - "public.data" // register for any kind of data. - }); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - _backBuffer?.Dispose(); - _backBuffer = null; - } - base.Dispose(disposing); - } - - public override bool ConformsToProtocol(IntPtr protocol) - { - var rv = base.ConformsToProtocol(protocol); - return rv; - } - - public override bool IsOpaque => false; - - public override void DrawRect(CGRect dirtyRect) - { - lock (SyncRoot) - _nonUiRedrawQueued = false; - Dispatcher.UIThread.RunJobs(DispatcherPriority.Render); - lock (SyncRoot) - { - if (_backBuffer != null) - { - using (var context = NSGraphicsContext.CurrentContext.GraphicsPort) - { - context.SetFillColor(255, 255, 255, 255); - context.FillRect(new CGRect(default(CGPoint), LogicalSize)); - context.TranslateCTM(0, LogicalSize.Height - _backBuffer.LogicalSize.Height); - context.DrawImage(new CGRect(default(CGPoint), _backBuffer.LogicalSize), _backBuffer.Image); - context.Flush(); - NSGraphicsContext.CurrentContext.FlushGraphics(); - } - } - } - _tl.Paint?.Invoke(dirtyRect.ToAvaloniaRect()); - } - - public void SetBackBufferImage(SavedImage image) - { - lock (SyncRoot) - { - _backBuffer?.Dispose(); - _backBuffer = image; - if (image == null) - return; - - if (_nonUiRedrawQueued) - return; - _nonUiRedrawQueued = true; - Dispatcher.UIThread.Post( - () => - { - lock (SyncRoot) - { - if (!_nonUiRedrawQueued) - return; - _nonUiRedrawQueued = false; - } - SetNeedsDisplayInRect(Frame); - Display(); - }, DispatcherPriority.Render); - - } - } - - [Export("viewDidChangeBackingProperties:")] - public void ViewDidChangeBackingProperties() - { - _tl?.ScalingChanged?.Invoke(_tl.Scaling); - } - - void UpdateCursor() - { - ResetCursorRects(); - if (_cursor != null) - { - AddCursorRect(Frame, _cursor); - if (_isMouseOver) - _cursor.Set(); - } - } - - static readonly NSCursor ArrowCursor = NSCursor.ArrowCursor; - - public void SetCursor(NSCursor cursor) - { - _cursor = cursor ?? ArrowCursor; - UpdateCursor(); - } - - private NSDragOperation SendRawDragEvent(NSDraggingInfo sender, RawDragEventType type) - { - Action input = _tl.Input; - IDragDropDevice dragDevice = _tl._dragDevice; - IInputRoot root = _tl?.InputRoot; - if (root == null || dragDevice == null || input == null) - return NSDragOperation.None; - - var dragOp = DraggingInfo.ConvertDragOperation(sender.DraggingSourceOperationMask); - DraggingInfo info = new DraggingInfo(sender); - - var pt = TranslateLocalPoint(info.Location); - var args = new RawDragEvent(dragDevice, type, root, pt, info, dragOp, GetModifiers(NSEvent.CurrentModifierFlags)); - input(args); - return DraggingInfo.ConvertDragOperation(args.Effects); - } - - public override NSDragOperation DraggingEntered(NSDraggingInfo sender) - { - return SendRawDragEvent(sender, RawDragEventType.DragEnter); - } - - public override NSDragOperation DraggingUpdated(NSDraggingInfo sender) - { - return SendRawDragEvent(sender, RawDragEventType.DragOver); - } - - public override void DraggingExited(NSDraggingInfo sender) - { - SendRawDragEvent(sender, RawDragEventType.DragLeave); - } - - public override bool PrepareForDragOperation(NSDraggingInfo sender) - { - return SendRawDragEvent(sender, RawDragEventType.DragOver) != NSDragOperation.None; - } - - public override bool PerformDragOperation(NSDraggingInfo sender) - { - return SendRawDragEvent(sender, RawDragEventType.Drop) != NSDragOperation.None; - } - - - public override void SetFrameSize(CGSize newSize) - { - lock (SyncRoot) - { - base.SetFrameSize(newSize); - LogicalSize = Frame.Size; - PixelSize = ConvertSizeToBacking(LogicalSize); - } - - if (_area != null) - { - RemoveTrackingArea(_area); - _area.Dispose(); - } - _area = new NSTrackingArea(new CGRect(default(CGPoint), newSize), - NSTrackingAreaOptions.ActiveAlways | - NSTrackingAreaOptions.MouseMoved | - NSTrackingAreaOptions.EnabledDuringMouseDrag, this, null); - AddTrackingArea(_area); - UpdateCursor(); - _tl?.Resized?.Invoke(_tl.ClientSize); - Dispatcher.UIThread.RunJobs(DispatcherPriority.Layout); - } - - InputModifiers GetModifiers(NSEventModifierMask mod) - { - var rv = new InputModifiers(); - if (mod.HasFlag(NSEventModifierMask.ControlKeyMask)) - rv |= InputModifiers.Control; - if (mod.HasFlag(NSEventModifierMask.ShiftKeyMask)) - rv |= InputModifiers.Shift; - if (mod.HasFlag(NSEventModifierMask.AlternateKeyMask)) - rv |= InputModifiers.Alt; - if (mod.HasFlag(NSEventModifierMask.CommandKeyMask)) - rv |= InputModifiers.Windows; - - if (_isLeftPressed) - rv |= InputModifiers.LeftMouseButton; - if (_isMiddlePressed) - rv |= InputModifiers.MiddleMouseButton; - if (_isRightPressed) - rv |= InputModifiers.RightMouseButton; - return rv; - } - - public Point TranslateLocalPoint(Point pt) => pt.WithY(Bounds.Height - pt.Y); - - Vector GetDelta(NSEvent ev) - { - var rv = new Vector(ev.ScrollingDeltaX, ev.ScrollingDeltaY); - //TODO: Verify if handling of HasPreciseScrollingDeltas - // is required (touchpad or magic-mouse is needed) - return rv; - } - - uint GetTimeStamp(NSEvent ev) => (uint) (ev.Timestamp * 1000); - - void MouseEvent(NSEvent ev, RawMouseEventType type) - { - BecomeFirstResponder(); - var loc = TranslateLocalPoint(ConvertPointToView(ev.LocationInWindow, this).ToAvaloniaPoint()); - var ts = GetTimeStamp(ev); - var mod = GetModifiers(ev.ModifierFlags); - if (type == RawMouseEventType.Wheel) - { - var delta = GetDelta(ev); - // ReSharper disable CompareOfFloatsByEqualityOperator - if (delta.X == 0 && delta.Y == 0) - return; - // ReSharper restore CompareOfFloatsByEqualityOperator - _tl.OnInput(new RawMouseWheelEventArgs(_mouse, ts, _tl.InputRoot, loc, - delta, mod)); - } - else - _tl.OnInput(new RawMouseEventArgs(_mouse, ts, _tl.InputRoot, type, loc, mod)); - } - - public override void MouseMoved(NSEvent theEvent) - { - MouseEvent(theEvent, RawMouseEventType.Move); - base.MouseMoved(theEvent); - } - - public override void MouseDragged(NSEvent theEvent) - { - MouseEvent(theEvent, RawMouseEventType.Move); - base.MouseDragged(theEvent); - } - - public override void OtherMouseDragged(NSEvent theEvent) - { - MouseEvent(theEvent, RawMouseEventType.Move); - base.OtherMouseDragged(theEvent); - } - - public override void RightMouseDragged(NSEvent theEvent) - { - MouseEvent(theEvent, RawMouseEventType.Move); - base.RightMouseDragged(theEvent); - } - - public NSEvent LastMouseDownEvent { get; private set; } - - public override void MouseDown(NSEvent theEvent) - { - _isLeftPressed = true; - LastMouseDownEvent = theEvent; - MouseEvent(theEvent, RawMouseEventType.LeftButtonDown); - LastMouseDownEvent = null; - base.MouseDown(theEvent); - } - - public override void RightMouseDown(NSEvent theEvent) - { - _isRightPressed = true; - MouseEvent(theEvent, RawMouseEventType.RightButtonDown); - base.RightMouseDown(theEvent); - } - - public override void OtherMouseDown(NSEvent theEvent) - { - _isMiddlePressed = true; - MouseEvent(theEvent, RawMouseEventType.MiddleButtonDown); - base.OtherMouseDown(theEvent); - } - - public override void MouseUp(NSEvent theEvent) - { - _isLeftPressed = false; - MouseEvent(theEvent, RawMouseEventType.LeftButtonUp); - base.MouseUp(theEvent); - } - - public override void RightMouseUp(NSEvent theEvent) - { - _isRightPressed = false; - MouseEvent(theEvent, RawMouseEventType.RightButtonUp); - base.RightMouseUp(theEvent); - } - - public override void OtherMouseUp(NSEvent theEvent) - { - _isMiddlePressed = false; - MouseEvent(theEvent, RawMouseEventType.MiddleButtonUp); - base.OtherMouseUp(theEvent); - } - - public override void ScrollWheel(NSEvent theEvent) - { - MouseEvent(theEvent, RawMouseEventType.Wheel); - base.ScrollWheel(theEvent); - } - - public override void MouseExited(NSEvent theEvent) - { - _isMouseOver = false; - MouseEvent(theEvent, RawMouseEventType.LeaveWindow); - base.MouseExited(theEvent); - } - - public override void MouseEntered(NSEvent theEvent) - { - _isMouseOver = true; - base.MouseEntered(theEvent); - } - - void KeyboardEvent(RawKeyEventType type, NSEvent ev) - { - var code = KeyTransform.TransformKeyCode(ev.KeyCode); - if (!code.HasValue) - return; - _tl.OnInput(new RawKeyEventArgs(_keyboard, GetTimeStamp(ev), - type, code.Value, GetModifiers(ev.ModifierFlags))); - } - - public override void KeyDown(NSEvent theEvent) - { - KeyboardEvent(RawKeyEventType.KeyDown, theEvent); - InputContext.HandleEvent(theEvent); - base.KeyDown(theEvent); - } - - public override void KeyUp(NSEvent theEvent) - { - KeyboardEvent(RawKeyEventType.KeyUp, theEvent); - base.KeyUp(theEvent); - } - - - - #region NSTextInputClient - - public override bool AcceptsFirstResponder() => true; - - public bool HasMarkedText - { - [Export("hasMarkedText")] get => false; - } - - public NSRange MarkedRange - { - [Export("markedRange")] get => new NSRange(NSRange.NotFound, 0); - } - - public NSRange SelectedRange - { - [Export("selectedRange")] get => new NSRange(NSRange.NotFound, 0); - } - - [Export("setMarkedText:selectedRange:replacementRange:")] - public void SetMarkedText(NSString str, NSRange a1, NSRange a2) - { - - } - - [Export("unmarkText")] - public void UnmarkText() - { - - } - - public NSArray ValidAttributesForMarkedText - { - [Export("validAttributesForMarkedText")] get => new NSArray(); - } - - [Export("attributedSubstringForProposedRange:actualRange:")] - public NSAttributedString AttributedSubstringForProposedRange(NSRange range, IntPtr wat) - { - return new NSAttributedString(""); - } - - [Export("insertText:replacementRange:")] - public void InsertText(NSString str, NSRange range) - { - //TODO: timestamp - _tl.OnInput(new RawTextInputEventArgs(_keyboard, 0, str.ToString())); - } - - [Export("characterIndexForPoint:")] - public uint CharacterIndexForPoint(CGPoint pt) - { - return 0; - } - - [Export("firstRectForCharacterRange:actualRange:")] - public CGRect FirstRectForCharacterRange(NSRange range, IntPtr wat) - { - return new CGRect(); - } - - #endregion - } - - public IInputRoot InputRoot { get; private set; } - - public abstract Size ClientSize { get; } - - public double Scaling - { - get - { - if (View.Window == null) - return 1; - return View.Window.BackingScaleFactor; - } - } - - public IEnumerable Surfaces => new[] {this}; - public IMouseDevice MouseDevice => _mouse; - - public Action Input { get; set; } - public Action Paint { get; set; } - public Action Resized { get; set; } - public Action ScalingChanged { get; set; } - public Action Closed { get; set; } - - - public virtual void Dispose() - { - Closed?.Invoke(); - Closed = null; - View.Dispose(); - } - - public IRenderer CreateRenderer(IRenderRoot root) => - MonoMacPlatform.UseDeferredRendering - ? new DeferredRenderer(root, AvaloniaLocator.Current.GetService()) - : (IRenderer) new ImmediateRenderer(root); - - public void Invalidate(Rect rect) - { - if (!MonoMacPlatform.UseDeferredRendering) - View.SetNeedsDisplayInRect(View.Frame); - } - - public abstract Point PointToClient(Point point); - - public abstract Point PointToScreen(Point point); - - public void SetCursor(IPlatformHandle cursor) => View.SetCursor((cursor as Cursor)?.Native); - - public void SetInputRoot(IInputRoot inputRoot) => InputRoot = inputRoot; - - public ILockedFramebuffer Lock() => new EmulatedFramebuffer(View); - } -} diff --git a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs b/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs deleted file mode 100644 index d3053a6af1..0000000000 --- a/src/OSX/Avalonia.MonoMac/WindowBaseImpl.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System; -using Avalonia.Controls; -using Avalonia.Input.Raw; -using Avalonia.Platform; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; -using MonoMac.Foundation; -using MonoMac.ObjCRuntime; - -namespace Avalonia.MonoMac -{ - class WindowBaseImpl : TopLevelImpl, IWindowBaseImpl - { - private readonly ManagedWindowResizeDragHelper _managedDrag; - public CustomWindow Window { get; private set; } - - private bool _closed; - - public WindowBaseImpl() - { - _managedDrag = new ManagedWindowResizeDragHelper(this, _ => { }, ResizeForManagedDrag); - // ReSharper disable once VirtualMemberCallInConstructor - Window = CreateCustomWindow(); - Window.StyleMask = NSWindowStyle.Titled; - Window.BackingType = NSBackingStore.Buffered; - Window.ContentView = View; - // ReSharper disable once VirtualMemberCallInConstructor - Window.Delegate = CreateWindowDelegate(); - } - - public class CustomWindow : NSWindow - { - readonly WindowBaseImpl _impl; - - public CustomWindow(WindowBaseImpl impl) - { - _impl = impl; - } - - public override void BecomeKeyWindow() - { - _impl.Activated?.Invoke(); - base.BecomeKeyWindow(); - } - - public override void ResignKeyWindow() - { - _impl.Deactivated?.Invoke(); - base.ResignKeyWindow(); - } - - private bool _canBecomeKeyAndMain; - public override bool CanBecomeKeyWindow => _canBecomeKeyAndMain; - public override bool CanBecomeMainWindow => _canBecomeKeyAndMain; - - public void SetCanBecomeKeyAndMain() => _canBecomeKeyAndMain = true; - } - - protected virtual CustomWindow CreateCustomWindow() => new CustomWindow(this); - protected virtual NSWindowDelegate CreateWindowDelegate() => new WindowBaseDelegate(this); - - public class WindowBaseDelegate : NSWindowDelegate - { - readonly WindowBaseImpl _impl; - public WindowBaseDelegate(WindowBaseImpl impl) - { - _impl = impl; - } - - public override void DidMoved(global::MonoMac.Foundation.NSNotification notification) - { - _impl.PositionChanged?.Invoke(_impl.Position); - } - - public override bool WindowShouldClose(NSObject sender) - { - bool? preventClose = _impl.Closing?.Invoke(); - return preventClose != true; - } - - public override void WillClose(global::MonoMac.Foundation.NSNotification notification) - { - _impl._closed = true; - _impl.Closed?.Invoke(); - } - - public override CGRect WillUseStandardFrame(NSWindow window, CGRect newFrame) - { - if (_impl is WindowImpl w && w.UndecoratedIsMaximized && w.UndecoratedLastUnmaximizedFrame.HasValue) - return w.UndecoratedLastUnmaximizedFrame.Value; - return window.Screen.VisibleFrame; - } - - public override bool ShouldZoom(NSWindow window, CGRect newFrame) - { - return true; - } - - public override void DidResize(NSNotification notification) - { - _impl.OnResized(); - } - } - - /// - /// As you can't combine NSWindowDelegate overrides and events this is a workaround - /// - protected virtual void OnResized() - { - } - - public Point Position - { - get => Window.Frame.ToAvaloniaRect().BottomLeft.ConvertPointY(); - set => Window.SetFrameTopLeftPoint(value.ToMonoMacPoint().ConvertPointY()); - } - - - protected virtual NSWindowStyle GetStyle() => NSWindowStyle.Borderless; - - protected void UpdateStyle() => Window.StyleMask = GetStyle(); - - - IPlatformHandle IWindowBaseImpl.Handle => new PlatformHandle(Window.Handle, "NSWindow"); - public Size MaxClientSize => NSScreen.Screens[0].Frame.ToAvaloniaRect().Size; - public Action PositionChanged { get; set; } - public Action Deactivated { get; set; } - public Action Activated { get; set; } - public Func Closing { get; set; } - - public override Size ClientSize => Window.ContentRectFor(Window.Frame).Size.ToAvaloniaSize(); - - - public void Show() => Window.MakeKeyAndOrderFront(Window); - - public void Hide() => Window?.OrderOut(Window); - - public void SetTopmost(bool value) => Window.Level = value ? NSWindowLevel.Floating : NSWindowLevel.Normal; - - public void BeginMoveDrag() - { - var ev = View.LastMouseDownEvent; - if (ev == null) - return; - var handle = Selector.GetHandle("performWindowDragWithEvent:"); - Messaging.void_objc_msgSend_IntPtr(Window.Handle, handle, ev.Handle); - } - - public void BeginResizeDrag(WindowEdge edge) - { - var screenPoint = NSEvent.CurrentMouseLocation.ConvertPointY().ToAvaloniaPoint(); - _managedDrag.BeginResizeDrag(edge, PointToClient(screenPoint)); - } - - protected override void OnInput(RawInputEventArgs args) - { - if (_managedDrag.PreprocessInputEvent(ref args)) - return; - base.OnInput(args); - } - - public void Activate() => Window.MakeKeyWindow(); - - public void ResizeForManagedDrag(Rect rc) - { - var frame = new CGRect(rc.X, rc.Position.ConvertPointY().Y - rc.Height, rc.Width, rc.Height); - Window.SetFrame(frame, true); - } - - public void Resize(Size clientSize) - { - var pos = Position; - Window.SetContentSize(clientSize.ToMonoMacSize()); - Position = pos; - } - - public void SetMinMaxSize(Size minSize, Size maxSize) - { - } - - public IScreenImpl Screen - { - get; - } = new ScreenImpl(); - - public override Point PointToClient(Point point) - { - var cocoaScreenPoint = point.ToMonoMacPoint().ConvertPointY(); - var cocoaViewPoint = Window.ConvertScreenToBase(cocoaScreenPoint).ToAvaloniaPoint(); - return View.TranslateLocalPoint(cocoaViewPoint); - } - - public override Point PointToScreen(Point point) - { - var cocoaViewPoint = View.TranslateLocalPoint(point).ToMonoMacPoint(); - var cocoaScreenPoint = Window.ConvertBaseToScreen(cocoaViewPoint); - return cocoaScreenPoint.ConvertPointY().ToAvaloniaPoint(); - } - - public override void Dispose() - { - if (!_closed) - Window.Close(); - Window.Dispose(); - base.Dispose(); - } - } -} diff --git a/src/OSX/Avalonia.MonoMac/WindowImpl.cs b/src/OSX/Avalonia.MonoMac/WindowImpl.cs deleted file mode 100644 index f276e07c99..0000000000 --- a/src/OSX/Avalonia.MonoMac/WindowImpl.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using Avalonia.Controls; -using Avalonia.Platform; -using Avalonia.Threading; -using MonoMac.AppKit; -using MonoMac.CoreGraphics; - -namespace Avalonia.MonoMac -{ - class WindowImpl : WindowBaseImpl, IWindowImpl - { - public bool IsDecorated = true; - public bool IsResizable = true; - public CGRect? UndecoratedLastUnmaximizedFrame; - - private WindowState _lastWindowState; - - public WindowImpl() - { - // Post UpdateStyle to UIThread otherwise for as yet unknown reason. - // The window becomes transparent to mouse clicks except a 100x100 square - // at the top left. (danwalmsley) - Dispatcher.UIThread.Post(() => - { - UpdateStyle(); - }); - - Window.SetCanBecomeKeyAndMain(); - } - - - protected override void OnResized() - { - var windowState = Window.IsMiniaturized ? WindowState.Minimized - : (IsZoomed ? WindowState.Maximized : WindowState.Normal); - - if (windowState != _lastWindowState) - { - _lastWindowState = windowState; - WindowStateChanged?.Invoke(windowState); - } - } - - public WindowState WindowState - { - get - { - if (Window.IsMiniaturized) - return WindowState.Minimized; - if (IsZoomed) - return WindowState.Maximized; - return WindowState.Normal; - } - set - { - if (value == WindowState.Maximized) - { - if (Window.IsMiniaturized) - Window.Deminiaturize(Window); - if (!IsZoomed) - DoZoom(); - } - else if (value.HasFlag(WindowState.Minimized)) - Window.Miniaturize(Window); - else - { - if (Window.IsMiniaturized) - Window.Deminiaturize(Window); - if (IsZoomed) - DoZoom(); - } - } - } - - public Action WindowStateChanged { get; set; } - - bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized; - - public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame; - - void DoZoom() - { - if (IsDecorated) - Window.PerformZoom(Window); - else - { - if (!UndecoratedIsMaximized) - UndecoratedLastUnmaximizedFrame = Window.Frame; - Window.Zoom(Window); - } - } - - public void SetIcon(IWindowIconImpl icon) - { - //No-OP, see http://stackoverflow.com/a/7038671/2231814 - } - - public void ShowTaskbarIcon(bool value) - { - //No-OP, there is no such this as taskbar in OSX - } - - protected override NSWindowStyle GetStyle() - { - var windowStyle = NSWindowStyle.Borderless; - - if (IsDecorated) - windowStyle |= NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Titled; - - if (IsResizable) - windowStyle |= NSWindowStyle.Resizable; - - return windowStyle; - } - - public void SetSystemDecorations(bool enabled) - { - IsDecorated = enabled; - UpdateStyle(); - } - - public void CanResize(bool value) - { - IsResizable = value; - UpdateStyle(); - } - - public void SetTitle(string title) => Window.Title = title; - - class ModalDisposable : IDisposable - { - readonly WindowImpl _impl; - readonly IntPtr _modalSession; - bool disposed; - - public ModalDisposable(WindowImpl impl, IntPtr modalSession) - { - _impl = impl; - _modalSession = modalSession; - } - - public void Continue() - { - if (disposed) - return; - - var response = (NSRunResponse)NSApplication.SharedApplication.RunModalSession(_modalSession); - if (response == NSRunResponse.Continues) - { - Dispatcher.UIThread.Post(Continue, DispatcherPriority.ContextIdle); - } - else - { - Logging.Logger.Log(Logging.LogEventLevel.Debug, "MonoMac", this, "Modal session ended"); - } - } - - public void Dispose() - { - Logging.Logger.Log(Logging.LogEventLevel.Debug, "MonoMac", this, "ModalDisposable disposed"); - _impl.Window.OrderOut(_impl.Window); - NSApplication.SharedApplication.EndModalSession(_modalSession); - disposed = true; - } - } - - public IDisposable ShowDialog() - { - var session = NSApplication.SharedApplication.BeginModalSession(Window); - var disposable = new ModalDisposable(this, session); - Dispatcher.UIThread.Post(disposable.Continue, DispatcherPriority.ContextIdle); - - return disposable; - } - } -} From 8883c45584a3ebb5a6bcfe08b6aaf0d69ed78fe9 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 23 Oct 2018 16:41:48 +0100 Subject: [PATCH 066/197] add avalonia.native package --- packages.cake | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages.cake b/packages.cake index b2e6291662..b7a7ab57bd 100644 --- a/packages.cake +++ b/packages.cake @@ -446,7 +446,24 @@ public class Packages }, BasePath = context.Directory("./src/Linux/"), OutputDirectory = parameters.NugetRoot - } + }, + /////////////////////////////////////////////////////////////////////////////// + // Avalonia.Native + /////////////////////////////////////////////////////////////////////////////// + new NuGetPackSettings() + { + Id = "Avalonia.Native", + Dependencies = new [] + { + new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version } + }, + Files = new [] + { + new NuSpecContent { Source = "Avalonia.Native.dll", Target = "lib/netstandard2.0" } + }, + BasePath = context.Directory("./src/Avalonia.Native/bin/" + parameters.DirSuffix + "/netstandard2.0"), + OutputDirectory = parameters.NugetRoot + }, }; var nuspecNuGetSettingInterop = new NuGetPackSettings() From 038e37767b1d84128bf418a1b2028217c35f35b6 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 23 Oct 2018 17:16:44 +0100 Subject: [PATCH 067/197] add an avalonia.native nuspec file --- packages.cake | 2 +- src/Avalonia.Native/Avalonia.Native.nuspec | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Native/Avalonia.Native.nuspec diff --git a/packages.cake b/packages.cake index b7a7ab57bd..4d6b5f6771 100644 --- a/packages.cake +++ b/packages.cake @@ -150,7 +150,7 @@ public class Packages nuspec.Symbols = false; nuspec.NoPackageAnalysis = true; nuspec.Description = "The Avalonia UI framework"; - nuspec.Copyright = "Copyright 2015"; + nuspec.Copyright = "Copyright 2018"; nuspec.Tags = new [] { "Avalonia" }; }); diff --git a/src/Avalonia.Native/Avalonia.Native.nuspec b/src/Avalonia.Native/Avalonia.Native.nuspec new file mode 100644 index 0000000000..8e84a1852f --- /dev/null +++ b/src/Avalonia.Native/Avalonia.Native.nuspec @@ -0,0 +1,22 @@ + + + + Avalonia.Native + $avalonia-version$ + Avalonia Team + stevenk + false + http://opensource.org/licenses/MIT + https://github.com/AvaloniaUI/Avalonia + The Avalonia UI framework + Copyright 2018 + Avalonia + + + + + + + + + \ No newline at end of file From ac2e19c522ac32619d710e0513abe5a56c7fb872 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 23 Oct 2018 17:27:01 +0100 Subject: [PATCH 068/197] add a nuspec for avalonia native and make it an artifact for second stage --- azure-pipelines.yml | 4 ++++ src/Avalonia.Native/{ => nuget}/Avalonia.Native.nuspec | 0 2 files changed, 4 insertions(+) rename src/Avalonia.Native/{ => nuget}/Avalonia.Native.nuspec (100%) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1eb7e226c8..af364288c3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -61,6 +61,10 @@ jobs: inputs: pathToPublish: '$(Build.SourcesDirectory)/artifacts/bin' artifactName: 'BinariesOSX' + - task: PublishBuildArtifacts@1 + inputs: + pathToPublish: '$(Build.SourcesDirectory)/src/Avalonia.Native/nuget' + artifactName: 'Avalonia.Native.Nuspec' - job: Windows pool: diff --git a/src/Avalonia.Native/Avalonia.Native.nuspec b/src/Avalonia.Native/nuget/Avalonia.Native.nuspec similarity index 100% rename from src/Avalonia.Native/Avalonia.Native.nuspec rename to src/Avalonia.Native/nuget/Avalonia.Native.nuspec From 6ebe3adc46f46df29ee4b2056900933e2f9ddcfb Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 23 Oct 2018 17:53:18 +0100 Subject: [PATCH 069/197] fix nuspec --- src/Avalonia.Native/nuget/Avalonia.Native.nuspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Native/nuget/Avalonia.Native.nuspec b/src/Avalonia.Native/nuget/Avalonia.Native.nuspec index 8e84a1852f..cea692b7ae 100644 --- a/src/Avalonia.Native/nuget/Avalonia.Native.nuspec +++ b/src/Avalonia.Native/nuget/Avalonia.Native.nuspec @@ -2,7 +2,7 @@ Avalonia.Native - $avalonia-version$ + $version$ Avalonia Team stevenk false @@ -12,11 +12,11 @@ Copyright 2018 Avalonia - + - - + + \ No newline at end of file From e6ef3268193a805b1966938a1daae3a4b3ca20db Mon Sep 17 00:00:00 2001 From: nopara73 Date: Tue, 23 Oct 2018 19:03:14 +0200 Subject: [PATCH 070/197] Resolve g_application_id_is_valid Gtk3 warning --- src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs b/src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs index 9604e9975b..8444e509fd 100644 --- a/src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs +++ b/src/Gtk/Avalonia.Gtk3/Gtk3Platform.cs @@ -66,7 +66,7 @@ namespace Avalonia.Gtk3 DisplayClassName = Utf8Buffer.StringFromPtr(Native.GTypeName(Marshal.ReadIntPtr(Marshal.ReadIntPtr(disp)))); - using (var utf = new Utf8Buffer("avalonia.app." + Guid.NewGuid())) + using (var utf = new Utf8Buffer($"avalonia.app.a{Guid.NewGuid().ToString("N")}")) App = Native.GtkApplicationNew(utf, 0); //Mark current thread as UI thread s_tlsMarker = true; From fea66108e8eeb7939d547250e9abe2c5ab8e749e Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 23 Oct 2018 19:56:40 +0100 Subject: [PATCH 071/197] fix nuspec --- src/Avalonia.Native/nuget/Avalonia.Native.nuspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Native/nuget/Avalonia.Native.nuspec b/src/Avalonia.Native/nuget/Avalonia.Native.nuspec index cea692b7ae..bd7344f91c 100644 --- a/src/Avalonia.Native/nuget/Avalonia.Native.nuspec +++ b/src/Avalonia.Native/nuget/Avalonia.Native.nuspec @@ -2,7 +2,7 @@ Avalonia.Native - $version$ + $avalonia-version$ Avalonia Team stevenk false @@ -12,7 +12,7 @@ Copyright 2018 Avalonia - + From 4aaee5360202dad62c8f68c3552a606e99cce809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Tue, 23 Oct 2018 23:15:26 +0200 Subject: [PATCH 072/197] Updated Cake and script tools and addins --- build.cake | 41 ++--------------------------------------- tools/packages.config | 2 +- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/build.cake b/build.cake index 56653109ae..d653e9da58 100644 --- a/build.cake +++ b/build.cake @@ -3,8 +3,8 @@ /////////////////////////////////////////////////////////////////////////////// #addin "nuget:?package=NuGet.Core&version=2.14.0" -#tool "nuget:?package=NuGet.CommandLine&version=4.3.0" -#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2017.1.20170613.162720" +#tool "nuget:?package=NuGet.CommandLine&version=4.7.1" +#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.2.3" /////////////////////////////////////////////////////////////////////////////// // TOOLS @@ -311,42 +311,6 @@ Task("Publish-NuGet-Impl") Information("Publish-NuGet Task failed, but continuing with next Task..."); }); -Task("Inspect-Impl") - .WithCriteria((context, data) => data.Parameters.IsRunningOnWindows) - .Does(() => -{ - var badIssues = new []{"PossibleNullReferenceException"}; - var whitelist = new []{"tests", "src\\android", "src\\ios", - "src\\markup\\avalonia.markup.xaml\\portablexaml\\portable.xaml.github"}; - Information("Running code inspections"); - - var exitCode = StartProcess(Context.Tools.Resolve("inspectcode.exe"), - new ProcessSettings - { - Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln", - RedirectStandardOutput = true - }); - - Information("Analyzing report"); - var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml")); - var failBuild = false; - foreach(var xml in doc.Descendants("Issue")) - { - var typeId = xml.Attribute("TypeId").Value.ToString(); - if(badIssues.Contains(typeId)) - { - var file = xml.Attribute("File").Value.ToString().ToLower(); - if(whitelist.Any(wh => file.StartsWith(wh))) - continue; - var line = xml.Attribute("Line").Value.ToString(); - Error(typeId + " - " + file + " on line " + line); - failBuild = true; - } - } - if(failBuild) - throw new Exception("Issues found"); -}); - /////////////////////////////////////////////////////////////////////////////// // TARGETS /////////////////////////////////////////////////////////////////////////////// @@ -364,7 +328,6 @@ Task("Run-Tests") Task("Package") .IsDependentOn("Run-Tests") - .IsDependentOn("Inspect-Impl") .IsDependentOn("Create-NuGet-Packages-Impl"); Task("AppVeyor") diff --git a/tools/packages.config b/tools/packages.config index 3c65df896f..05018882e8 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - + From 70812de8e234d4ef141a386f5be90efed46b24c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Tue, 23 Oct 2018 23:26:53 +0200 Subject: [PATCH 073/197] Install castxml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index d80d24f32c..b0c0c807cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ mono: - 5.2.0 dotnet: 2.1.200 script: + - sudo apt-get update + - sudo apt-get install castxml - ./build.sh --target "Travis" --configuration "Release" notifications: email: false From 963453a1ff9341b82f0546586791f33856097e5b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 24 Oct 2018 08:24:12 +0200 Subject: [PATCH 074/197] Size window in response to WM_DPICHANGED. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 45120fa21b..d78c213299 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -497,9 +497,15 @@ namespace Avalonia.Win32 case UnmanagedMethods.WindowsMessage.WM_DPICHANGED: var dpi = ToInt32(wParam) & 0xffff; var newDisplayRect = Marshal.PtrToStructure(lParam); - Position = new Point(newDisplayRect.left, newDisplayRect.top); _scaling = dpi / 96.0; ScalingChanged?.Invoke(_scaling); + SetWindowPos(hWnd, + IntPtr.Zero, + newDisplayRect.left, + newDisplayRect.top, + newDisplayRect.right - newDisplayRect.left, + newDisplayRect.bottom - newDisplayRect.top, + SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOACTIVATE); return IntPtr.Zero; case UnmanagedMethods.WindowsMessage.WM_KEYDOWN: From 9be4c05e31718e72294b7bde9c6077cb01d35a64 Mon Sep 17 00:00:00 2001 From: wieslawsoltes Date: Wed, 24 Oct 2018 07:03:45 +0000 Subject: [PATCH 075/197] Use theme resources --- src/Avalonia.Themes.Default/ContextMenu.xaml | 2 +- src/Avalonia.Themes.Default/Expander.xaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Themes.Default/ContextMenu.xaml b/src/Avalonia.Themes.Default/ContextMenu.xaml index 41d53aa6b3..61392a869b 100644 --- a/src/Avalonia.Themes.Default/ContextMenu.xaml +++ b/src/Avalonia.Themes.Default/ContextMenu.xaml @@ -1,5 +1,5 @@ diff --git a/src/Avalonia.Themes.Default/Button.xaml b/src/Avalonia.Themes.Default/Button.xaml index 94fcce5e0c..698ddec2a8 100644 --- a/src/Avalonia.Themes.Default/Button.xaml +++ b/src/Avalonia.Themes.Default/Button.xaml @@ -1,7 +1,7 @@ diff --git a/src/Avalonia.Themes.Default/CalendarDayButton.xaml b/src/Avalonia.Themes.Default/CalendarDayButton.xaml index 4a971ef0cb..2d79e62a75 100644 --- a/src/Avalonia.Themes.Default/CalendarDayButton.xaml +++ b/src/Avalonia.Themes.Default/CalendarDayButton.xaml @@ -100,10 +100,10 @@ diff --git a/src/Avalonia.Themes.Default/DatePicker.xaml b/src/Avalonia.Themes.Default/DatePicker.xaml index 93bafdb56f..3fb760d35b 100644 --- a/src/Avalonia.Themes.Default/DatePicker.xaml +++ b/src/Avalonia.Themes.Default/DatePicker.xaml @@ -29,7 +29,7 @@ HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0" - Background="{DynamicResource ThemeControlLightBrush}" + Background="{DynamicResource ThemeControlLowBrush}" ColumnDefinitions="*,*,*,*" RowDefinitions="23*,19*,19*,19*" ClipToBounds="False"> @@ -47,12 +47,12 @@ Grid.Row="1" Grid.RowSpan="3" BorderThickness="1" - BorderBrush="{DynamicResource ThemeBorderDarkBrush}" + BorderBrush="{DynamicResource ThemeBorderHighBrush}" CornerRadius=".5" /> + Foreground="{DynamicResource ThemeBorderHighBrush}"> - + @@ -123,7 +123,7 @@ diff --git a/src/Avalonia.Themes.Default/DropDown.xaml b/src/Avalonia.Themes.Default/DropDown.xaml index c57d961f4b..451f1c2f23 100644 --- a/src/Avalonia.Themes.Default/DropDown.xaml +++ b/src/Avalonia.Themes.Default/DropDown.xaml @@ -52,6 +52,6 @@ \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Expander.xaml b/src/Avalonia.Themes.Default/Expander.xaml index b34189bac0..d63f785e77 100644 --- a/src/Avalonia.Themes.Default/Expander.xaml +++ b/src/Avalonia.Themes.Default/Expander.xaml @@ -108,7 +108,7 @@ - - - - + + + Apply Geometry Clip diff --git a/samples/RenderDemo/Pages/DrawingPage.xaml b/samples/RenderDemo/Pages/DrawingPage.xaml index ee892774f0..3473591d9d 100644 --- a/samples/RenderDemo/Pages/DrawingPage.xaml +++ b/samples/RenderDemo/Pages/DrawingPage.xaml @@ -98,7 +98,7 @@ - + - + \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/external b/src/Avalonia.HtmlRenderer/external new file mode 160000 index 0000000000..43df78f4d1 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/external @@ -0,0 +1 @@ +Subproject commit 43df78f4d1bb09d05021f062cb15e939e3e1771d From 0094c4cf8741dba0f21e95a7aa865d7c6650a124 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Mon, 29 Oct 2018 19:10:38 +0800 Subject: [PATCH 136/197] Fix unit test by specifying the font in the test image. --- tests/Avalonia.RenderTests/Controls/TextBlockTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs index 80b850635d..63e1578145 100644 --- a/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs +++ b/tests/Avalonia.RenderTests/Controls/TextBlockTests.cs @@ -25,6 +25,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls { Decorator target = new Decorator { + FontFamily = new FontFamily("Courier New"), Padding = new Thickness(8), Width = 200, Height = 200, From 57a896e878569ab72802214bb92c7744cac00122 Mon Sep 17 00:00:00 2001 From: Jumar Macato Date: Mon, 29 Oct 2018 19:12:38 +0800 Subject: [PATCH 137/197] Remove hardcoded fonts on our theme definition. --- src/Avalonia.HtmlRenderer/external | 1 + src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml | 1 - src/Avalonia.Themes.Default/Window.xaml | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) create mode 160000 src/Avalonia.HtmlRenderer/external diff --git a/src/Avalonia.HtmlRenderer/external b/src/Avalonia.HtmlRenderer/external new file mode 160000 index 0000000000..43df78f4d1 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/external @@ -0,0 +1 @@ +Subproject commit 43df78f4d1bb09d05021f062cb15e939e3e1771d diff --git a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml index de364c0108..bc06ab010e 100644 --- a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml +++ b/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml @@ -1,6 +1,5 @@ From d783d3e1fc5d09316653c88f7b7ff23b179bb0da Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 6 Nov 2018 10:26:01 +0100 Subject: [PATCH 183/197] do not focus scrollbar --- src/Avalonia.Themes.Default/ScrollBar.xaml | 24 ++++++++++++------- src/Avalonia.Themes.Default/ScrollViewer.xaml | 6 +++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Themes.Default/ScrollBar.xaml b/src/Avalonia.Themes.Default/ScrollBar.xaml index e128e33368..ae40929573 100644 --- a/src/Avalonia.Themes.Default/ScrollBar.xaml +++ b/src/Avalonia.Themes.Default/ScrollBar.xaml @@ -7,7 +7,8 @@ + Grid.Column="0" + Focusable="False"> @@ -21,11 +22,13 @@ Orientation="{TemplateBinding Orientation}"> + Classes="repeattrack" + Focusable="False"/> + Classes="repeattrack" + Focusable="False"/> @@ -38,7 +41,8 @@ + Grid.Column="2" + Focusable="False"> @@ -58,7 +62,8 @@ + Grid.Column="0" + Focusable="False"> @@ -72,11 +77,13 @@ Orientation="{TemplateBinding Orientation}"> + Classes="repeattrack" + Focusable="False"/> + Classes="repeattrack" + Focusable="False"/> @@ -89,7 +96,8 @@ + Grid.Column="2" + Focusable="False"> diff --git a/src/Avalonia.Themes.Default/ScrollViewer.xaml b/src/Avalonia.Themes.Default/ScrollViewer.xaml index c493fb32e3..63440921d6 100644 --- a/src/Avalonia.Themes.Default/ScrollViewer.xaml +++ b/src/Avalonia.Themes.Default/ScrollViewer.xaml @@ -19,14 +19,16 @@ Value="{TemplateBinding HorizontalScrollBarValue, Mode=TwoWay}" ViewportSize="{TemplateBinding HorizontalScrollBarViewportSize}" Visibility="{TemplateBinding HorizontalScrollBarVisibility}" - Grid.Row="1"/> + Grid.Row="1" + Focusable="False"/> + Grid.Column="1" + Focusable="False"/> From c05edaebdccb8ba2df445685aa93bb291c3899f5 Mon Sep 17 00:00:00 2001 From: Stano Turza Date: Tue, 6 Nov 2018 10:26:25 +0100 Subject: [PATCH 184/197] scrollbar PageUp/PageDown handling --- src/Avalonia.Controls/Primitives/ScrollBar.cs | 14 ++++++++++++++ src/Avalonia.Controls/ScrollViewer.cs | 15 +++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Avalonia.Controls/Primitives/ScrollBar.cs b/src/Avalonia.Controls/Primitives/ScrollBar.cs index 1e290107bb..f0d8c81808 100644 --- a/src/Avalonia.Controls/Primitives/ScrollBar.cs +++ b/src/Avalonia.Controls/Primitives/ScrollBar.cs @@ -128,6 +128,20 @@ namespace Avalonia.Controls.Primitives } } + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Key == Key.PageUp) + { + LargeDecrement(); + e.Handled = true; + } + else if (e.Key == Key.PageDown) + { + LargeIncrement(); + e.Handled = true; + } + } + protected override void OnTemplateApplied(TemplateAppliedEventArgs e) { base.OnTemplateApplied(e); diff --git a/src/Avalonia.Controls/ScrollViewer.cs b/src/Avalonia.Controls/ScrollViewer.cs index 39854e0071..264b1fd2ce 100644 --- a/src/Avalonia.Controls/ScrollViewer.cs +++ b/src/Avalonia.Controls/ScrollViewer.cs @@ -4,6 +4,7 @@ using System; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; +using Avalonia.Input; namespace Avalonia.Controls { @@ -441,5 +442,19 @@ namespace Avalonia.Controls RaisePropertyChanged(VerticalScrollBarValueProperty, 0, VerticalScrollBarValue); RaisePropertyChanged(VerticalScrollBarViewportSizeProperty, 0, VerticalScrollBarViewportSize); } + + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Key == Key.PageUp) + { + VerticalScrollBarValue = Math.Max(_offset.Y - _viewport.Height, 0); + e.Handled = true; + } + else if (e.Key == Key.PageDown) + { + VerticalScrollBarValue = Math.Min(_offset.Y + _viewport.Height, VerticalScrollBarMaximum); + e.Handled = true; + } + } } } From aefec666116e3a4baf2163942b806b6f4b9dcf9a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 6 Nov 2018 10:36:08 +0000 Subject: [PATCH 185/197] [OSX] reset lastKeyHandled flag when performKeyEquivalent is called since this indicated a key being pressed also. --- native/Avalonia.Native/src/OSX/window.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 76243493c4..362b765b3d 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -963,7 +963,11 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent - (BOOL)performKeyEquivalent:(NSEvent *)event { - return _lastKeyHandled; + bool result = _lastKeyHandled; + + _lastKeyHandled = false; + + return result; } - (void)keyDown:(NSEvent *)event From c1fda553e6ac7c841e34feb678f986f405a1fd75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Tue, 6 Nov 2018 12:01:20 +0100 Subject: [PATCH 186/197] Fix header styles --- samples/ControlCatalog/App.xaml | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index 95d515ec60..19a22bb6ed 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -2,23 +2,16 @@ - - - - - - + + From d07217b59a1920bbb5f6f44d04249bd96e65e0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Tue, 6 Nov 2018 12:01:36 +0100 Subject: [PATCH 187/197] Enable full theme support for main view --- samples/ControlCatalog/MainView.xaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index ec3bf799b4..effb805728 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -1,6 +1,9 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Background="{DynamicResource ThemeBackgroundBrush}" + TextBlock.Foreground="{DynamicResource ThemeForegroundBrush}" + TextBlock.FontSize="{DynamicResource FontSizeNormal}"> From 779cdec09356f7c825b5f70f87b5b4732a6b0036 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 7 Nov 2018 15:24:49 +0000 Subject: [PATCH 188/197] initial work to fixing clipboard text encoding issues. --- native/Avalonia.Native/inc/avalonia-native.h | 8 ++- .../project.pbxproj | 6 ++ native/Avalonia.Native/src/OSX/AvnString.h | 14 +++++ native/Avalonia.Native/src/OSX/AvnString.mm | 55 +++++++++++++++++++ native/Avalonia.Native/src/OSX/clipboard.mm | 15 +++-- src/Avalonia.Native/ClipboardImpl.cs | 9 +-- 6 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 native/Avalonia.Native/src/OSX/AvnString.h create mode 100644 native/Avalonia.Native/src/OSX/AvnString.mm diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 0c965b7498..1d5a112929 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -173,6 +173,12 @@ public: virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) = 0; }; +AVNCOM(IAvnString, 17) : IUnknown +{ + virtual HRESULT GetPointer(void**retOut) = 0; + virtual HRESULT GetLength(int*ret) = 0; +}; + AVNCOM(IAvnWindowBase, 02) : IUnknown { virtual HRESULT Show() = 0; @@ -315,7 +321,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { - virtual HRESULT GetText (void** retOut) = 0; + virtual HRESULT GetText (IAvnString** ppv ) = 0; virtual HRESULT SetText (char* text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj index bd8ac481a8..cc74d5669f 100644 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; }; 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; }; + 37DDA9B0219330F8002E132B /* AvnString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DDA9AF219330F8002E132B /* AvnString.mm */; }; 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; }; 5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; }; 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; }; @@ -26,6 +27,8 @@ 37A517B22159597E00FBA241 /* Screens.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Screens.mm; sourceTree = ""; }; 37C09D8721580FE4006A6758 /* SystemDialogs.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemDialogs.mm; sourceTree = ""; }; 37C09D8A21581EF2006A6758 /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = window.h; sourceTree = ""; }; + 37DDA9AF219330F8002E132B /* AvnString.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnString.mm; sourceTree = ""; }; + 37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.h; sourceTree = ""; }; 37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = ""; }; 5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = ""; }; 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = ""; }; @@ -65,6 +68,8 @@ AB7A61E62147C814003C5833 = { isa = PBXGroup; children = ( + 37DDA9B121933371002E132B /* AvnString.h */, + 37DDA9AF219330F8002E132B /* AvnString.mm */, 37A4E71A2178846A00EACBCD /* headers */, AB573DC3217605E400D389A2 /* gl.mm */, 5BF943652167AD1D009CAE35 /* cursor.h */, @@ -161,6 +166,7 @@ files = ( 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */, 5B21A982216530F500CEE36E /* cursor.mm in Sources */, + 37DDA9B0219330F8002E132B /* AvnString.mm in Sources */, AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, 37A517B32159597E00FBA241 /* Screens.mm in Sources */, diff --git a/native/Avalonia.Native/src/OSX/AvnString.h b/native/Avalonia.Native/src/OSX/AvnString.h new file mode 100644 index 0000000000..9a8f5a1318 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/AvnString.h @@ -0,0 +1,14 @@ +// +// AvnString.h +// Avalonia.Native.OSX +// +// Created by Dan Walmsley on 07/11/2018. +// Copyright © 2018 Avalonia. All rights reserved. +// + +#ifndef AvnString_h +#define AvnString_h + +extern IAvnString* CreateAvnString(NSString* string); + +#endif /* AvnString_h */ diff --git a/native/Avalonia.Native/src/OSX/AvnString.mm b/native/Avalonia.Native/src/OSX/AvnString.mm new file mode 100644 index 0000000000..a16c286634 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/AvnString.mm @@ -0,0 +1,55 @@ +// +// AvnString.m +// Avalonia.Native.OSX +// +// Created by Dan Walmsley on 07/11/2018. +// Copyright © 2018 Avalonia. All rights reserved. +// + +#include "common.h" + +class AvnStringImpl : public virtual ComSingleObject +{ +private: + NSString* _string; + +public: + FORWARD_IUNKNOWN() + + AvnStringImpl(NSString* string) + { + _string = string; + } + + virtual HRESULT GetPointer(void**retOut) override + { + @autoreleasepool + { + if(retOut == nullptr) + { + return E_POINTER; + } + + *retOut = (void*)_string.UTF8String; + + return S_OK; + } + } + + virtual HRESULT GetLength(int*retOut) override + { + if(retOut == nullptr) + { + return E_POINTER; + } + + *retOut = (int)_string.length; + + return S_OK; + } +}; + +IAvnString* CreateAvnString(NSString* string) +{ + return new AvnStringImpl(string); +} diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index 19e5c25801..f941e8ca6c 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -2,20 +2,25 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. #include "common.h" +#include "AvnString.h" class Clipboard : public ComSingleObject { public: FORWARD_IUNKNOWN() - virtual HRESULT GetText (void** retOut) override + virtual HRESULT GetText (IAvnString** retOut) override { @autoreleasepool { - NSString *str = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]; - *retOut = (void *)str.UTF8String; - } + if(retOut == nullptr) + { + return E_POINTER; + } + + *retOut = CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); - return S_OK; + return S_OK; + } } virtual HRESULT SetText (char* text) override diff --git a/src/Avalonia.Native/ClipboardImpl.cs b/src/Avalonia.Native/ClipboardImpl.cs index d54bc95fbb..a2a1416645 100644 --- a/src/Avalonia.Native/ClipboardImpl.cs +++ b/src/Avalonia.Native/ClipboardImpl.cs @@ -24,12 +24,13 @@ namespace Avalonia.Native return Task.CompletedTask; } - public Task GetTextAsync() + public unsafe Task GetTextAsync() { - var outPtr = _native.GetText(); - var text = Marshal.PtrToStringAnsi(outPtr); + var text = _native.GetText(); - return Task.FromResult(text); + var result = System.Text.Encoding.UTF8.GetString((byte*)text.GetPointer(), text.GetLength()); + + return Task.FromResult(result); } public Task SetTextAsync(string text) From b224a21433f58540fdd24aa6ebb99bba1aa3e4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Wed, 7 Nov 2018 16:24:55 +0100 Subject: [PATCH 189/197] Set window Foreground property to enable theming --- src/Avalonia.Themes.Default/Window.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Default/Window.xaml b/src/Avalonia.Themes.Default/Window.xaml index 611f8ebece..2514422ce8 100644 --- a/src/Avalonia.Themes.Default/Window.xaml +++ b/src/Avalonia.Themes.Default/Window.xaml @@ -1,5 +1,6 @@ \ No newline at end of file + From c9aff424a5c3fd4c18042100b1c63513db4918b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Wed, 7 Nov 2018 16:25:27 +0100 Subject: [PATCH 190/197] Remove not required properties --- samples/ControlCatalog/MainView.xaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index effb805728..ec3bf799b4 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -1,9 +1,6 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> From c3ec5c543f7cc3d2083120a6267ee0ebff7aef03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Wed, 7 Nov 2018 17:16:01 +0100 Subject: [PATCH 191/197] Added user control styling support --- src/Avalonia.Controls/UserControl.cs | 2 +- src/Avalonia.Themes.Default/DefaultTheme.xaml | 1 + src/Avalonia.Themes.Default/UserControl.xaml | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/Avalonia.Themes.Default/UserControl.xaml diff --git a/src/Avalonia.Controls/UserControl.cs b/src/Avalonia.Controls/UserControl.cs index e063a65e09..3f51f613a4 100644 --- a/src/Avalonia.Controls/UserControl.cs +++ b/src/Avalonia.Controls/UserControl.cs @@ -28,7 +28,7 @@ namespace Avalonia.Controls } /// - Type IStyleable.StyleKey => typeof(ContentControl); + Type IStyleable.StyleKey => typeof(UserControl); /// void INameScope.Register(string name, object element) diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 2b9132ee56..0bd91c8f1e 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -35,6 +35,7 @@ + diff --git a/src/Avalonia.Themes.Default/UserControl.xaml b/src/Avalonia.Themes.Default/UserControl.xaml new file mode 100644 index 0000000000..2bf5f19698 --- /dev/null +++ b/src/Avalonia.Themes.Default/UserControl.xaml @@ -0,0 +1,15 @@ + From 06a6059a1e4b50204ca5162b7eb1f77045b79a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Wed, 7 Nov 2018 17:27:56 +0100 Subject: [PATCH 192/197] Fix failing test --- tests/Avalonia.Controls.UnitTests/UserControlTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs index 738c54594e..36fde09cdb 100644 --- a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs @@ -23,7 +23,7 @@ namespace Avalonia.Controls.UnitTests { Styles = { - new Style(x => x.OfType()) + new Style(x => x.OfType()) { Setters = new[] { From 55486faa43c363852bb1d04ed24d6405a10e9ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Wed, 7 Nov 2018 17:32:04 +0100 Subject: [PATCH 193/197] Fix type --- tests/Avalonia.Controls.UnitTests/UserControlTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs index 36fde09cdb..6da771217c 100644 --- a/tests/Avalonia.Controls.UnitTests/UserControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/UserControlTests.cs @@ -40,7 +40,7 @@ namespace Avalonia.Controls.UnitTests private FuncControlTemplate GetTemplate() { - return new FuncControlTemplate(parent => + return new FuncControlTemplate(parent => { return new Border { From f6d080feecd1a68ce5ba8028dbdab37b5e8e8264 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:20:51 +0000 Subject: [PATCH 194/197] [OSX] fix pasting from clipboard --- native/Avalonia.Native/inc/avalonia-native.h | 6 +++--- native/Avalonia.Native/src/OSX/AvnString.mm | 4 ++-- native/Avalonia.Native/src/OSX/clipboard.mm | 11 ++--------- src/Avalonia.Native/ClipboardImpl.cs | 9 +++++---- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 1d5a112929..b9e16e6643 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -175,8 +175,8 @@ public: AVNCOM(IAvnString, 17) : IUnknown { - virtual HRESULT GetPointer(void**retOut) = 0; - virtual HRESULT GetLength(int*ret) = 0; + virtual HRESULT Pointer(void**retOut) = 0; + virtual HRESULT Length(int*ret) = 0; }; AVNCOM(IAvnWindowBase, 02) : IUnknown @@ -321,7 +321,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { - virtual HRESULT GetText (IAvnString** ppv ) = 0; + virtual IAvnString* GetText () = 0; virtual HRESULT SetText (char* text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/AvnString.mm b/native/Avalonia.Native/src/OSX/AvnString.mm index a16c286634..b491cf2a92 100644 --- a/native/Avalonia.Native/src/OSX/AvnString.mm +++ b/native/Avalonia.Native/src/OSX/AvnString.mm @@ -21,7 +21,7 @@ public: _string = string; } - virtual HRESULT GetPointer(void**retOut) override + virtual HRESULT Pointer(void**retOut) override { @autoreleasepool { @@ -36,7 +36,7 @@ public: } } - virtual HRESULT GetLength(int*retOut) override + virtual HRESULT Length(int*retOut) override { if(retOut == nullptr) { diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index f941e8ca6c..8f95433f64 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -8,18 +8,11 @@ class Clipboard : public ComSingleObject { public: FORWARD_IUNKNOWN() - virtual HRESULT GetText (IAvnString** retOut) override + virtual IAvnString* GetText () override { @autoreleasepool { - if(retOut == nullptr) - { - return E_POINTER; - } - - *retOut = CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); - - return S_OK; + return CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); } } diff --git a/src/Avalonia.Native/ClipboardImpl.cs b/src/Avalonia.Native/ClipboardImpl.cs index a2a1416645..9a49976683 100644 --- a/src/Avalonia.Native/ClipboardImpl.cs +++ b/src/Avalonia.Native/ClipboardImpl.cs @@ -26,11 +26,12 @@ namespace Avalonia.Native public unsafe Task GetTextAsync() { - var text = _native.GetText(); - - var result = System.Text.Encoding.UTF8.GetString((byte*)text.GetPointer(), text.GetLength()); + using (var text = _native.GetText()) + { + var result = System.Text.Encoding.UTF8.GetString((byte*)text.Pointer(), text.Length()); - return Task.FromResult(result); + return Task.FromResult(result); + } } public Task SetTextAsync(string text) From d06ed4a7dba0729b303b84b02014052b0b0e0718 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:38:28 +0000 Subject: [PATCH 195/197] [OSX] correctly use UTF8 encoded text for passing strings. SetTitle on Window, SetText on Clipboard. --- native/Avalonia.Native/inc/avalonia-native.h | 4 ++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ native/Avalonia.Native/src/OSX/clipboard.mm | 4 ++-- native/Avalonia.Native/src/OSX/window.mm | 4 ++-- src/Avalonia.Native/ClipboardImpl.cs | 6 +++++- src/Avalonia.Native/WindowImpl.cs | 6 +++++- 6 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index b9e16e6643..f353509346 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -216,7 +216,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase virtual HRESULT ShowDialog (IUnknown**ppv) = 0; virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetHasDecorations(bool value) = 0; - virtual HRESULT SetTitle (const char* title) = 0; + virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0; virtual HRESULT GetWindowState(AvnWindowState*ret) = 0; @@ -322,7 +322,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { virtual IAvnString* GetText () = 0; - virtual HRESULT SetText (char* text) = 0; + virtual HRESULT SetText (void* utf8Text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index 8f95433f64..be77ff52d8 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -16,13 +16,13 @@ public: } } - virtual HRESULT SetText (char* text) override + virtual HRESULT SetText (void* utf8String) override { @autoreleasepool { NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; [pasteBoard clearContents]; - [pasteBoard setString:@(text) forType:NSPasteboardTypeString]; + [pasteBoard setString:[NSString stringWithUTF8String:(const char*)utf8String] forType:NSPasteboardTypeString]; } return S_OK; diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 362b765b3d..16b21efcd5 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -530,11 +530,11 @@ private: } } - virtual HRESULT SetTitle (const char* title) override + virtual HRESULT SetTitle (void* utf8title) override { @autoreleasepool { - _lastTitle = [NSString stringWithUTF8String:title]; + _lastTitle = [NSString stringWithUTF8String:(const char*)utf8title]; [Window setTitle:_lastTitle]; [Window setTitleVisibility:NSWindowTitleVisible]; diff --git a/src/Avalonia.Native/ClipboardImpl.cs b/src/Avalonia.Native/ClipboardImpl.cs index 9a49976683..c756a6d9c2 100644 --- a/src/Avalonia.Native/ClipboardImpl.cs +++ b/src/Avalonia.Native/ClipboardImpl.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; using Avalonia.Input.Platform; using Avalonia.Native.Interop; +using Avalonia.Platform.Interop; namespace Avalonia.Native { @@ -40,7 +41,10 @@ namespace Avalonia.Native if (text != null) { - _native.SetText(text); + using (var buffer = new Utf8Buffer(text)) + { + _native.SetText(buffer.DangerousGetHandle()); + } } return Task.CompletedTask; diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 5d30408e52..3b1b4ff3f9 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -5,6 +5,7 @@ using System; using Avalonia.Controls; using Avalonia.Native.Interop; using Avalonia.Platform; +using Avalonia.Platform.Interop; namespace Avalonia.Native { @@ -68,7 +69,10 @@ namespace Avalonia.Native public void SetTitle(string title) { - _native.SetTitle(title); + using (var buffer = new Utf8Buffer(title)) + { + _native.SetTitle(buffer.DangerousGetHandle()); + } } public WindowState WindowState From 5af1c1784a8dd58491b9e834bf97c489a235cc95 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:43:36 +0000 Subject: [PATCH 196/197] [Avalonia.Native OSX] fix api for clipboard --- native/Avalonia.Native/inc/avalonia-native.h | 2 +- native/Avalonia.Native/src/OSX/clipboard.mm | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index f353509346..0e3edaa2dc 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -321,7 +321,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { - virtual IAvnString* GetText () = 0; + virtual HRESULT GetText (IAvnString**ppv) = 0; virtual HRESULT SetText (void* utf8Text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index be77ff52d8..53c1fe3c2c 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -8,11 +8,18 @@ class Clipboard : public ComSingleObject { public: FORWARD_IUNKNOWN() - virtual IAvnString* GetText () override + virtual HRESULT GetText (IAvnString**ppv) override { @autoreleasepool { - return CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); + if(ppv == nullptr) + { + return E_POINTER; + } + + *ppv = CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); + + return S_OK; } } From 7762fa6079b06850087b1d1888b7b3a463b2541a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:46:52 +0000 Subject: [PATCH 197/197] remove plist file --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - -