From a85e70a124d15c567bd0ebe1e2c2a95e063f16a1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 Jan 2017 22:57:33 +0000 Subject: [PATCH 01/15] Remove CoverTaskbarWhenMaximized property from Window. --- src/Avalonia.Controls/Window.cs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 6755dee073..40c52a748d 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -64,13 +64,6 @@ namespace Avalonia.Controls public static readonly StyledProperty HasSystemDecorationsProperty = AvaloniaProperty.Register(nameof(HasSystemDecorations), true); - /// - /// Sets if the window should cover the taskbar when maximized. Only applies to Windows - /// with HasSystemDecorations = false. - /// - public static readonly StyledProperty CoverTaskbarOnMaximizeProperty = - AvaloniaProperty.Register(nameof(CoverTaskbarOnMaximize), true); - /// /// Defines the property. /// @@ -97,9 +90,6 @@ namespace Avalonia.Controls HasSystemDecorationsProperty.Changed.AddClassHandler( (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue)); - CoverTaskbarOnMaximizeProperty.Changed.AddClassHandler( - (s, e) => s.PlatformImpl.SetCoverTaskbarWhenMaximized((bool)e.NewValue)); - IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl)); } @@ -168,16 +158,6 @@ namespace Avalonia.Controls set { SetValue(HasSystemDecorationsProperty, value); } } - /// - /// Sets if the window should cover the taskbar when maximized. Only applies to Windows - /// with HasSystemDecorations = false. - /// - public bool CoverTaskbarOnMaximize - { - get { return GetValue(CoverTaskbarOnMaximizeProperty); } - set { SetValue(CoverTaskbarOnMaximizeProperty, value); } - } - /// /// Gets or sets the minimized/maximized state of the window. /// From c09755cfbff589dfbf74ee47bf2501988a24bf9f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 Jan 2017 22:57:56 +0000 Subject: [PATCH 02/15] Remove SetCoverTaskbarWhenMaximized method from IWindowImpl --- src/Avalonia.Controls/Platform/IWindowImpl.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index fd2feb539f..609e9834cb 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -35,11 +35,6 @@ namespace Avalonia.Platform /// void SetSystemDecorations(bool enabled); - /// - /// When system decorations are disabled sets if the maximized state covers the entire screen or just the working area. - /// - void SetCoverTaskbarWhenMaximized(bool enable); - /// /// Sets the icon of this window. /// From 1394995927dc87c017dc3160e5c586e26f10da12 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 Jan 2017 23:02:01 +0000 Subject: [PATCH 03/15] Win32 WindowImpl now obeys taskbar when maximizing by default. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index db46538796..ed6d9c32d3 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -33,7 +33,6 @@ namespace Avalonia.Win32 private bool _trackingMouse; private bool _isActive; private bool _decorated = true; - private bool _coverTaskBarWhenMaximized = true; private double _scaling = 1; private WindowState _showWindowState; @@ -678,8 +677,6 @@ namespace Avalonia.Win32 { UnmanagedMethods.ShowWindowCommand command; - bool maximizeFillsDesktop = false; // otherwise we cover entire screen. - switch (state) { case WindowState.Minimized: @@ -687,11 +684,6 @@ namespace Avalonia.Win32 break; case WindowState.Maximized: command = ShowWindowCommand.Maximize; - - if (!_decorated && !_coverTaskBarWhenMaximized) - { - maximizeFillsDesktop = true; - } break; case WindowState.Normal: @@ -704,10 +696,7 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(_hwnd, command); - if (maximizeFillsDesktop) - { - MaximizeWithoutCoveringTaskbar(); - } + MaximizeWithoutCoveringTaskbar(); if (!Design.IsDesignMode) { @@ -751,15 +740,5 @@ namespace Avalonia.Win32 return (int)(ptr.ToInt64() & 0xffffffff); } - - public void SetCoverTaskbarWhenMaximized(bool enable) - { - _coverTaskBarWhenMaximized = enable; - - if (_showWindowState == WindowState.Maximized) - { - ShowWindow(WindowState.Maximized); - } - } } } From 80e42b5882ca5b7be9062b3a871c314a878c4e1e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 Jan 2017 23:04:06 +0000 Subject: [PATCH 04/15] Remove SetCoverTaskbarWhenMaximized from other backends. --- .../Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs | 5 ----- src/Gtk/Avalonia.Gtk/WindowImplBase.cs | 5 ----- src/iOS/Avalonia.iOS/AvaloniaView.cs | 5 ----- 3 files changed, 15 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs index 0e1540b5fd..f1c5d248ac 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -108,11 +108,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform { } - public void SetCoverTaskbarWhenMaximized(bool enable) - { - //Not supported - } - public void Invalidate(Rect rect) { if (Holder?.Surface?.IsValid == true) base.Invalidate(); diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs index 8641f2f431..a9ecfa4058 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs @@ -304,11 +304,6 @@ namespace Avalonia.Gtk args.RetVal = true; } - public void SetCoverTaskbarWhenMaximized(bool enable) - { - // No action neccesary on Gtk. - } - public void Dispose() { _window.Hide(); diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.cs b/src/iOS/Avalonia.iOS/AvaloniaView.cs index 67817ef62a..8b14d09573 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.cs @@ -170,11 +170,6 @@ namespace Avalonia.iOS //Not supported } - public void SetCoverTaskbarWhenMaximized(bool enable) - { - //Not supported - } - public override void TouchesEnded(NSSet touches, UIEvent evt) { var touch = touches.AnyObject as UITouch; From e486b27357e42b3a19954eee8c7d6c8e09866c9f Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 Jan 2017 23:16:59 +0000 Subject: [PATCH 05/15] Only call maximize without covering taskbar if we are in maximized state. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index ed6d9c32d3..1ddd1ed10f 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -696,7 +696,10 @@ namespace Avalonia.Win32 UnmanagedMethods.ShowWindow(_hwnd, command); - MaximizeWithoutCoveringTaskbar(); + if (state == WindowState.Maximized) + { + MaximizeWithoutCoveringTaskbar(); + } if (!Design.IsDesignMode) { From 8f3e56963a05ee6260a789ea802de39ea0e0c803 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 26 Jan 2017 23:52:59 +0100 Subject: [PATCH 06/15] Picked some style nits. --- .../Platform/SkiaPlatform/WindowImpl.cs | 6 +- .../Platform/Surfaces/ILockedFramebuffer.cs | 9 +-- .../Platform/IPlatformRenderInterface.cs | 4 +- src/Gtk/Avalonia.Cairo/CairoPlatform.cs | 2 +- src/Gtk/Avalonia.Gtk/FramebufferManager.cs | 5 +- src/Gtk/Avalonia.Gtk/WindowImplBase.cs | 13 ++-- .../Avalonia.Skia/PlatformRenderInterface.cs | 2 - .../Avalonia.Win32/WindowFramebuffer.cs | 71 +++++++++---------- src/Windows/Avalonia.Win32/WindowImpl.cs | 11 +-- src/iOS/Avalonia.iOS/AvaloniaView.cs | 5 +- 10 files changed, 59 insertions(+), 69 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs index 7816a8af27..0ce7bdca22 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs @@ -96,6 +96,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform IPlatformHandle ITopLevelImpl.Handle => this; + public IEnumerable Surfaces => new object[] { this }; + public void Activate() { } @@ -194,7 +196,5 @@ namespace Avalonia.Android.Platform.SkiaPlatform { // No window icons for mobile platforms } - - public IEnumerable Surfaces => new object[] {this}; - } + } } \ No newline at end of file diff --git a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs b/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs index e771401dfe..d6402d170d 100644 --- a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs +++ b/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Avalonia.Controls.Platform.Surfaces { @@ -12,22 +8,27 @@ namespace Avalonia.Controls.Platform.Surfaces /// Address of the first pixel /// IntPtr Address { get; } + /// /// Framebuffer width /// int Width { get; } + /// /// Framebuffer height /// int Height { get; } + /// /// Number of bytes per row /// int RowBytes { get; } + /// /// DPI of underling screen /// Size Dpi { get; } + /// /// Pixel format /// diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index 34600c145f..cdec0a07a1 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -41,7 +41,9 @@ namespace Avalonia.Platform /// /// Creates a renderer. /// - /// The list of native platform's surfaces that can be used for output. + /// + /// The list of native platform surfaces that can be used for output. + /// /// An . IRenderTarget CreateRenderTarget(IEnumerable surfaces); diff --git a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs index 8b3c6899d3..e6c493320f 100644 --- a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs +++ b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs @@ -59,7 +59,7 @@ namespace Avalonia.Cairo return new RenderTarget(accessor); throw new NotSupportedException(string.Format( - "Don't know how to create a Cairo renderer from any of provided surfaces")); + "Don't know how to create a Cairo renderer from any of the provided surfaces.")); } public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) diff --git a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs index 3da3c3d70c..72c977b2b4 100644 --- a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs +++ b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Avalonia.Controls.Platform.Surfaces; namespace Avalonia.Gtk @@ -11,6 +7,7 @@ namespace Avalonia.Gtk { private readonly WindowImplBase _window; private PixbufFramebuffer _fb; + public FramebufferManager(WindowImplBase window) { _window = window; diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs index bd48998dff..a8bd7836ec 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs @@ -3,15 +3,10 @@ using System; using System.Collections.Generic; -using System.Reactive.Disposables; -using System.Runtime.InteropServices; -using Gdk; -using Avalonia.Controls; -using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Platform; -using Avalonia.Input; -using Avalonia.Threading; +using Gdk; using Action = System.Action; using WindowEdge = Avalonia.Controls.WindowEdge; @@ -23,8 +18,6 @@ namespace Avalonia.Gtk { private IInputRoot _inputRoot; protected Gtk.Widget _window; - public Gtk.Widget Widget => _window; - public Gdk.Drawable CurrentDrawable { get; private set; } private FramebufferManager _framebuffer; private Gtk.IMContext _imContext; @@ -60,6 +53,8 @@ namespace Avalonia.Gtk } public IPlatformHandle Handle { get; private set; } + public Gtk.Widget Widget => _window; + public Gdk.Drawable CurrentDrawable { get; private set; } void OnRealized (object sender, EventArgs eventArgs) { diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index 56b334073b..4cfe1e3e40 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -55,8 +55,6 @@ namespace Avalonia.Skia return new Renderer(root, renderLoop); } - - public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) { if (width < 1) diff --git a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs index cd89c01131..f7ea79e78a 100644 --- a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs +++ b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs @@ -18,8 +18,7 @@ namespace Avalonia.Win32 { private readonly IntPtr _handle; private IntPtr _pBitmap; - UnmanagedMethods.BITMAPINFOHEADER _bmpInfo; - + private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo; public WindowFramebuffer(IntPtr handle, int width, int height) { @@ -38,7 +37,38 @@ namespace Avalonia.Win32 _pBitmap = Marshal.AllocHGlobal(width * height * 4); } + ~WindowFramebuffer() + { + Deallocate(); + } + + public IntPtr Address => _pBitmap; + public int RowBytes => Width * 4; + public PixelFormat Format => PixelFormat.Bgra8888; + + public Size Dpi + { + get + { + if (UnmanagedMethods.ShCoreAvailable) + { + uint dpix, dpiy; + + var monitor = UnmanagedMethods.MonitorFromWindow(_handle, + UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST); + if (UnmanagedMethods.GetDpiForMonitor( + monitor, + UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, + out dpix, + out dpiy) == 0) + { + return new Size(dpix, dpiy); + } + } + return new Size(96, 96); + } + } public int Width => _bmpInfo.biWidth; @@ -73,11 +103,9 @@ namespace Avalonia.Win32 return true; } - - public void Dispose() { - //It's not an *actual* dispose. This call meand "We are done drawing" + //It's not an *actual* dispose. This call means "We are done drawing" DrawToWindow(_handle); } @@ -89,38 +117,5 @@ namespace Avalonia.Win32 _pBitmap = IntPtr.Zero; } } - - ~WindowFramebuffer() - { - Deallocate(); - } - - public IntPtr Address => _pBitmap; - public int RowBytes => Width * 4; - public PixelFormat Format => PixelFormat.Bgra8888; - - public Size Dpi - { - get - { - if (UnmanagedMethods.ShCoreAvailable) - { - uint dpix, dpiy; - - var monitor = UnmanagedMethods.MonitorFromWindow(_handle, - UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST); - - if (UnmanagedMethods.GetDpiForMonitor( - monitor, - UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, - out dpix, - out dpiy) == 0) - { - return new Size(dpix, dpiy); - } - } - return new Size(96, 96); - } - } } } \ No newline at end of file diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 19a7ca5e58..90bc684292 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -38,6 +38,7 @@ namespace Avalonia.Win32 private double _scaling = 1; private WindowState _showWindowState; private FramebufferManager _framebuffer; + public WindowImpl() { CreateWindow(); @@ -164,6 +165,11 @@ namespace Avalonia.Win32 } } + public IEnumerable Surfaces => new object[] + { + Handle, _framebuffer + }; + public void Activate() { UnmanagedMethods.SetActiveWindow(_hwnd); @@ -764,10 +770,5 @@ namespace Avalonia.Win32 ShowWindow(WindowState.Maximized); } } - - public IEnumerable Surfaces => new object[] - { - Handle, _framebuffer - }; } } diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.cs b/src/iOS/Avalonia.iOS/AvaloniaView.cs index e9d095483b..1ef034b87c 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.cs @@ -149,6 +149,9 @@ namespace Avalonia.iOS } public Size MaxClientSize => Bounds.Size.ToAvalonia(); + + public IEnumerable Surfaces => new object[] { this }; + public void SetTitle(string title) { //Not supported @@ -232,8 +235,6 @@ namespace Avalonia.iOS public void SetIcon(IWindowIconImpl icon) { } - - public IEnumerable Surfaces => new object[]{this}; } class AvaloniaViewController : UIViewController From d4a967d0626a07c56b48e8b7dbba31ea2a0d52d6 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 27 Jan 2017 00:08:09 +0100 Subject: [PATCH 07/15] Missed a nit. --- src/Gtk/Avalonia.Gtk/WindowImplBase.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs index a8bd7836ec..c82d510c64 100644 --- a/src/Gtk/Avalonia.Gtk/WindowImplBase.cs +++ b/src/Gtk/Avalonia.Gtk/WindowImplBase.cs @@ -125,6 +125,13 @@ namespace Avalonia.Gtk public Action ScalingChanged { get; set; } + public IEnumerable Surfaces => new object[] + { + Handle, + new Func(() => CurrentDrawable), + _framebuffer + }; + public IPopupImpl CreatePopup() { return new PopupImpl(); @@ -316,12 +323,5 @@ namespace Avalonia.Gtk _window.Dispose(); _window = null; } - - public IEnumerable Surfaces => new object[] - { - Handle, - new Func(() => CurrentDrawable), - _framebuffer - }; } } From 714145b13d914c18319105b4bbac7bef98ba1fb0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 27 Jan 2017 00:58:24 +0100 Subject: [PATCH 08/15] Added SharpDX.Direct3D11 to nuspec. --- build.cake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.cake b/build.cake index e902c5d24e..a4be2dc9e0 100644 --- a/build.cake +++ b/build.cake @@ -197,6 +197,7 @@ var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault(). var SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1; var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1; var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1; +var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1; var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1; Information("Package: Serilog, version: {0}", SerilogVersion); @@ -206,6 +207,7 @@ Information("Package: System.Reactive, version: {0}", SystemReactiveVersion); Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion); Information("Package: SharpDX, version: {0}", SharpDXVersion); Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version); +Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version); Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion); var SetNuGetNuspecCommonProperties = new Action ((nuspec) => { @@ -441,6 +443,7 @@ var nuspecNuGetSettingsDesktop = new [] new NuSpecDependency() { Id = "Avalonia", Version = version }, new NuSpecDependency() { Id = "SharpDX", Version = SharpDXVersion }, new NuSpecDependency() { Id = "SharpDX.Direct2D1", Version = SharpDXDirect2D1Version }, + new NuSpecDependency() { Id = "SharpDX.Direct3D11", Version = SharpDXDirect3D11Version }, new NuSpecDependency() { Id = "SharpDX.DXGI", Version = SharpDXDXGIVersion } }, Files = new [] From 54721a6941679b55f2afa6a8bf3fa913e4cfb99a Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Fri, 27 Jan 2017 22:30:43 +0300 Subject: [PATCH 09/15] TwoWay binding by default for IsExpanded property in Expander control. fixes #865. --- src/Avalonia.Controls/Expander.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Expander.cs b/src/Avalonia.Controls/Expander.cs index 87eb427f3c..e7f75336f5 100644 --- a/src/Avalonia.Controls/Expander.cs +++ b/src/Avalonia.Controls/Expander.cs @@ -31,7 +31,8 @@ namespace Avalonia.Controls AvaloniaProperty.RegisterDirect( nameof(IsExpanded), o => o.IsExpanded, - (o, v) => o.IsExpanded = v); + (o, v) => o.IsExpanded = v, + defaultBindingMode: Data.BindingMode.TwoWay); static Expander() { From 65686fc00293bac46cea236b7d79a4d980c734d1 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 28 Jan 2017 18:17:30 +0300 Subject: [PATCH 10/15] Use ImageSurface instead of Pixbuf --- src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj | 4 +- src/Gtk/Avalonia.Gtk/FramebufferManager.cs | 6 +-- src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs | 58 ---------------------- src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs | 55 ++++++++++++++++++++ 4 files changed, 61 insertions(+), 62 deletions(-) delete mode 100644 src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs create mode 100644 src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs diff --git a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj index 2c10b1188b..540e70cee0 100644 --- a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj +++ b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj @@ -30,6 +30,8 @@ false + + @@ -50,7 +52,7 @@ - + diff --git a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs index 72c977b2b4..00a4727769 100644 --- a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs +++ b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs @@ -6,7 +6,7 @@ namespace Avalonia.Gtk class FramebufferManager : IFramebufferPlatformSurface, IDisposable { private readonly WindowImplBase _window; - private PixbufFramebuffer _fb; + private SurfaceFramebuffer _fb; public FramebufferManager(WindowImplBase window) { @@ -29,8 +29,8 @@ namespace Avalonia.Gtk if (_fb == null || _fb.Width != width || _fb.Height != height) { - _fb?.Dispose(); - _fb = new PixbufFramebuffer(width, height); + _fb?.Deallocate(); + _fb = new SurfaceFramebuffer(width, height); } _fb.SetDrawable(drawable); return _fb; diff --git a/src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs b/src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs deleted file mode 100644 index 76e9e8a307..0000000000 --- a/src/Gtk/Avalonia.Gtk/PixbufFramebuffer.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Avalonia.Controls.Platform.Surfaces; -using Avalonia.Platform; -using Gdk; - -namespace Avalonia.Gtk -{ - class PixbufFramebuffer : ILockedFramebuffer - { - private Pixbuf _pixbuf; - private Drawable _drawable; - - public PixbufFramebuffer(int width, int height) - { - _pixbuf = new Pixbuf(Gdk.Colorspace.Rgb, false, 8, width, height); - } - - public void SetDrawable(Drawable drawable) - { - _drawable = drawable; - } - - public void Deallocate() - { - _pixbuf.Dispose(); - _pixbuf = null; - } - - public void Dispose() - { - using (var gc = new Gdk.GC(_drawable)) - _drawable.DrawPixbuf(gc, _pixbuf, 0, 0, 0, 0, Width, Height, RgbDither.None, 0, 0); - _drawable = null; - } - - public IntPtr Address => _pixbuf.Pixels; - public int Width => _pixbuf.Width; - public int Height => _pixbuf.Height; - public int RowBytes => _pixbuf.Rowstride; - //TODO: Proper DPI detect - public Size Dpi => new Size(96, 96); - public PixelFormat Format - { - get - { - if (AvaloniaLocator.Current.GetService().GetRuntimeInfo().OperatingSystem == - OperatingSystemType.WinNT) - return PixelFormat.Bgra8888; - return PixelFormat.Rgba8888; - } - } - } -} - diff --git a/src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs b/src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs new file mode 100644 index 0000000000..7e6da0e76a --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/SurfaceFramebuffer.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; +using Cairo; +using Gdk; + +namespace Avalonia.Gtk +{ + class SurfaceFramebuffer : ILockedFramebuffer + { + private Drawable _drawable; + private ImageSurface _surface; + + public SurfaceFramebuffer(int width, int height) + { + _surface = new ImageSurface(Cairo.Format.RGB24, width, height); + } + + public void SetDrawable(Drawable drawable) + { + _drawable = drawable; + _surface.Flush(); + } + + public void Deallocate() + { + _surface.Dispose(); + _surface = null; + } + + public void Dispose() + { + using (var ctx = CairoHelper.Create(_drawable)) + { + _surface.MarkDirty(); + ctx.SetSourceSurface(_surface, 0, 0); + ctx.Paint(); + } + _drawable = null; + } + + public IntPtr Address => _surface.DataPtr; + public int Width => _surface.Width; + public int Height => _surface.Height; + public int RowBytes => _surface.Stride; + //TODO: Proper DPI detect + public Size Dpi => new Size(96, 96); + public PixelFormat Format => PixelFormat.Bgra8888; + } +} + From c446aaf5a6a364d26a32d9c92ba126d58c50ca41 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 28 Jan 2017 23:22:53 +0300 Subject: [PATCH 11/15] Removed IWindowImpl which was a lie, removed initialization hack, fixed rendering --- .../ControlCatalog.Android.csproj | 7 +- .../ControlCatalog.Android/MainActivity.cs | 24 ++---- .../Avalonia.Android/AndroidPlatform.cs | 25 +++--- .../AndroidThreadingInterface.cs | 12 ++- .../Avalonia.Android/Avalonia.Android.csproj | 7 +- .../Avalonia.Android/AvaloniaActivity.cs | 50 ++++++++++++ src/Android/Avalonia.Android/AvaloniaView.cs | 59 ++++++++++++++ .../Platform/SkiaPlatform/MainWindowImpl.cs | 44 ----------- .../{WindowImpl.cs => TopLevelImpl.cs} | 24 ++---- .../Platform/Specific/AvaloniaActivity.cs | 60 --------------- .../Helpers/AndroidKeyboardEventsHelper.cs | 2 +- .../Helpers/AndroidTouchEventsHelper.cs | 2 +- .../Platform/Specific/IAndroidActivity.cs | 12 --- .../Avalonia.AndroidTestApplication.csproj | 12 +-- .../MainActivity.cs | 32 ++------ .../Avalonia.Skia.Android.csproj | 1 + .../Avalonia.Skia.Android/NativeMethods.cs | 71 +++++++++++++++++ .../Avalonia.Skia.Android/RenderTarget.cs | 77 +++++++------------ src/Skia/Avalonia.Skia.Android/SkiaView.cs | 4 +- 19 files changed, 271 insertions(+), 254 deletions(-) create mode 100644 src/Android/Avalonia.Android/AvaloniaActivity.cs create mode 100644 src/Android/Avalonia.Android/AvaloniaView.cs delete mode 100644 src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs rename src/Android/Avalonia.Android/Platform/SkiaPlatform/{WindowImpl.cs => TopLevelImpl.cs} (86%) delete mode 100644 src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs delete mode 100644 src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs create mode 100644 src/Skia/Avalonia.Skia.Android/NativeMethods.cs diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 5b39aa3dfb..7dd09df73c 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -29,12 +29,15 @@ 4 True None - False + True False False - armeabi,armeabi-v7a,x86 + armeabi;armeabi-v7a;x86 Xamarin False + False + False + False pdbonly diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index 3f357b0e70..157609088f 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -1,9 +1,8 @@ using System; using Android.App; - using Android.OS; using Android.Content.PM; -using Avalonia.Android.Platform.Specific; +using Avalonia.Android; using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Markup.Xaml; @@ -17,29 +16,16 @@ namespace ControlCatalog.Android [Activity(Label = "ControlCatalog.Android", MainLauncher = true, Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance)] public class MainActivity : AvaloniaActivity { - public MainActivity() : base(typeof (App)) - { - - } - protected override void OnCreate(Bundle savedInstanceState) { - base.OnCreate(savedInstanceState); - - App app; - if (Avalonia.Application.Current != null) - app = (App)Avalonia.Application.Current; - else + if (Avalonia.Application.Current == null) { - app = new App(); - AppBuilder.Configure(app) + AppBuilder.Configure(new App()) .UseAndroid() - .UseSkia() .SetupWithoutStarting(); + Content = new MainView(); } - - var mainWindow = new MainWindow(); - app.Run(mainWindow); + base.OnCreate(savedInstanceState); } } } diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index afaa314e6c..5b3170a0c7 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -1,5 +1,8 @@ using System; using System.IO; +using System.Linq; +using Android.Content; +using Android.Views; using Avalonia.Android.Platform; using Avalonia.Android.Platform.Input; using Avalonia.Android.Platform.SkiaPlatform; @@ -8,6 +11,7 @@ using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Platform; +using Avalonia.Rendering; using Avalonia.Shared.PlatformSupport; using Avalonia.Skia; @@ -17,7 +21,8 @@ namespace Avalonia { public static T UseAndroid(this T builder) where T : AppBuilderBase, new() { - builder.UseWindowingSubsystem(Android.AndroidPlatform.Initialize, "Android"); + builder.UseWindowingSubsystem(() => Android.AndroidPlatform.Initialize(builder.Instance), "Android"); + builder.UseSkia(); return builder; } } @@ -25,7 +30,7 @@ namespace Avalonia namespace Avalonia.Android { - public class AndroidPlatform : IPlatformSettings, IWindowingPlatform + class AndroidPlatform : IPlatformSettings, IWindowingPlatform { public static readonly AndroidPlatform Instance = new AndroidPlatform(); public Size DoubleClickSize => new Size(4, 4); @@ -40,7 +45,7 @@ namespace Avalonia.Android _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; } - public static void Initialize() + public static void Initialize(Avalonia.Application app) { AvaloniaLocator.CurrentMutable .Bind().ToTransient() @@ -51,24 +56,22 @@ namespace Avalonia.Android .Bind().ToConstant(new AndroidThreadingInterface()) .Bind().ToTransient() .Bind().ToConstant(Instance) - .Bind().ToSingleton(); + .Bind().ToSingleton() + .Bind().ToConstant(new DefaultRenderLoop(60)) - SkiaPlatform.Initialize(); - } + .Bind().ToConstant(new AssetLoader(app.GetType().Assembly)); - public void Init(Type applicationType) - { - StandardRuntimePlatformServices.Register(applicationType.Assembly); + SkiaPlatform.Initialize(); } public IWindowImpl CreateWindow() { - return new WindowImpl(); + throw new NotSupportedException(); } public IEmbeddableWindowImpl CreateEmbeddableWindow() { - throw new NotImplementedException(); + throw new NotSupportedException(); } public IPopupImpl CreatePopup() diff --git a/src/Android/Avalonia.Android/AndroidThreadingInterface.cs b/src/Android/Avalonia.Android/AndroidThreadingInterface.cs index b4059e3114..6327be12a5 100644 --- a/src/Android/Avalonia.Android/AndroidThreadingInterface.cs +++ b/src/Android/Avalonia.Android/AndroidThreadingInterface.cs @@ -51,10 +51,16 @@ namespace Avalonia.Android scheduled = true; EnsureInvokeOnMainThread(() => { - tick(); - lock (l) + try { - scheduled = false; + tick(); + } + finally + { + lock (l) + { + scheduled = false; + } } }); } diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index 654cb13678..e84146ffb3 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -63,16 +63,15 @@ + + - - + - - diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs new file mode 100644 index 0000000000..a9b04c882b --- /dev/null +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; + +namespace Avalonia.Android +{ + public abstract class AvaloniaActivity : Activity + { + AvaloniaView _view; + object _content; + + protected override void OnCreate(Bundle savedInstanceState) + { + RequestWindowFeature(WindowFeatures.NoTitle); + _view = new AvaloniaView(this); + if(_content != null) + _view.Content = _content; + SetContentView(_view); + TakeKeyEvents(true); + base.OnCreate(savedInstanceState); + } + + public object Content + { + get + { + return _content; + } + set + { + _content = value; + if (_view != null) + _view.Content = value; + } + } + + public override bool DispatchKeyEvent(KeyEvent e) + { + return _view.DispatchKeyEvent(e); + } + } +} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs new file mode 100644 index 0000000000..71eea14a1d --- /dev/null +++ b/src/Android/Avalonia.Android/AvaloniaView.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Avalonia.Android.Platform.SkiaPlatform; +using Avalonia.Controls.Embedding; +using Avalonia.Platform; + +namespace Avalonia.Android +{ + public class AvaloniaView : FrameLayout + { + private readonly EmbeddableControlRoot _root; + private readonly ViewImpl _view; + + public AvaloniaView(Context context) : base(context) + { + _view = new ViewImpl(context); + AddView(_view); + _root = new EmbeddableControlRoot(_view); + _root.Prepare(); + } + + public object Content + { + get { return _root.Content; } + set { _root.Content = value; } + } + + public override bool DispatchKeyEvent(KeyEvent e) + { + return _view.DispatchKeyEvent(e); + } + + class ViewImpl : TopLevelImpl, IEmbeddableWindowImpl + { + public event Action LostFocus; + + public ViewImpl(Context context) : base(context) + { + Focusable = true; + FocusChange += ViewImpl_FocusChange; + } + + private void ViewImpl_FocusChange(object sender, FocusChangeEventArgs e) + { + if(!e.HasFocus) + LostFocus?.Invoke(); + } + } + } +} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs deleted file mode 100644 index 690c509b53..0000000000 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Android.Views; -using Avalonia.Android.Platform.Specific; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Platform; - -namespace Avalonia.Android.Platform.SkiaPlatform -{ - public class MainWindowImpl : - WindowImpl - , IWindowImpl - { - public MainWindowImpl() - { - } - - public new WindowState WindowState - { - get { return WindowState.Normal; } - set { } - } - - protected override void Init() - { - base.Init(); - - HandleEvents = true; - _keyboardHelper.ActivateAutoShowKeybord(); - } - - void ITopLevelImpl.Show() - { - (Parent as ViewGroup)?.RemoveAllViews(); - AvaloniaLocator.Current.GetService().ContentView = this; - //this.Visibility = ViewStates.Visible; - } - - void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) - { - base.SetInputRoot(inputRoot); - _keyboardHelper.UpdateKeyboardState(inputRoot); - } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs similarity index 86% rename from src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs rename to src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 17b1cfba0a..1687432bb3 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -14,25 +14,21 @@ using Avalonia.Controls; namespace Avalonia.Android.Platform.SkiaPlatform { - public class WindowImpl : SkiaView, IAndroidView, IWindowImpl, ISurfaceHolderCallback + class TopLevelImpl : SkiaView, IAndroidView, ITopLevelImpl, ISurfaceHolderCallback { - protected AndroidKeyboardEventsHelper _keyboardHelper; + protected AndroidKeyboardEventsHelper _keyboardHelper; - private AndroidTouchEventsHelper _touchHelper; + private AndroidTouchEventsHelper _touchHelper; - public WindowImpl(Context context) : base((Activity)context) + public TopLevelImpl(Context context) : base(context) { - _keyboardHelper = new AndroidKeyboardEventsHelper(this); - _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); + _keyboardHelper = new AndroidKeyboardEventsHelper(this); + _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); MaxClientSize = new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels); ClientSize = MaxClientSize; - Init(); - } - - public WindowImpl() : this(AvaloniaLocator.Current.GetService().Activity) - { } + void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) { @@ -46,11 +42,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform base.SurfaceChanged(holder, format, width, height); } - - protected virtual void Init() - { - } - + private bool _handleEvents; public bool HandleEvents diff --git a/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs b/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs deleted file mode 100644 index 4ccff10455..0000000000 --- a/src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using Android.App; -using Android.OS; -using Android.Views; -using Android.Widget; - -namespace Avalonia.Android.Platform.Specific -{ - public class AvaloniaActivity : Activity, IAndroidActivity - { - private IAndroidView _contentView; - - public AvaloniaActivity(Type applicationType) - { - AndroidPlatform.Instance.Init(applicationType); - } - - public Activity Activity => this; - - public IAndroidView ContentView - { - get - { - return this._contentView; - } - - set - { - this._contentView = value; - var fl = new FrameLayout(this); - fl.AddView(this._contentView.View); - //this.SetContentView(value.View); - this.SetContentView(fl); - } - } - - protected override void OnCreate(Bundle savedInstanceState) - { - AvaloniaLocator.CurrentMutable.Bind().ToConstant(this); - RequestWindowFeature(WindowFeatures.NoTitle); - base.OnCreate(savedInstanceState); - } - - public override void SetContentView(View view) - { - base.SetContentView(view); - TakeKeyEvents(true); - } - - public override bool DispatchKeyEvent(KeyEvent e) - { - if (_contentView != null) - { - _contentView.View.DispatchKeyEvent(e); - } - - return base.DispatchKeyEvent(e); - } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index 17e1f62e8c..7bac0ff814 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -12,7 +12,7 @@ using System.ComponentModel; namespace Avalonia.Android.Platform.Specific.Helpers { - public class AndroidKeyboardEventsHelper : IDisposable where TView : View, IWindowImpl, IAndroidView + public class AndroidKeyboardEventsHelper : IDisposable where TView : View, ITopLevelImpl, IAndroidView { private TView _view; private IInputElement _lastFocusedElement; diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs index c6d1833d2d..a448044ee6 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs @@ -8,7 +8,7 @@ using System; namespace Avalonia.Android.Platform.Specific.Helpers { - public class AndroidTouchEventsHelper : IDisposable where TView : View, IWindowImpl, IAndroidView + public class AndroidTouchEventsHelper : IDisposable where TView : View, ITopLevelImpl, IAndroidView { private TView _view; public bool HandleEvents { get; set; } diff --git a/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs b/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs deleted file mode 100644 index b2a999d4be..0000000000 --- a/src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Android.App; -using Android.Views; - -namespace Avalonia.Android.Platform.Specific -{ - public interface IAndroidActivity - { - Activity Activity { get; } - - IAndroidView ContentView { get; set; } - } -} \ No newline at end of file diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj index e004121323..ebe268adcf 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj +++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj @@ -20,7 +20,7 @@ Properties\AndroidManifest.xml - true + True full false bin\Debug\ @@ -29,16 +29,16 @@ 4 True None - - False + True False False - armeabi,armeabi-v7a,x86 - - + armeabi;armeabi-v7a;x86 Xamarin False True + False + False + False pdbonly diff --git a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs index ff27e12f6e..7973ad72e5 100644 --- a/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs +++ b/src/Android/Avalonia.AndroidTestApplication/MainActivity.cs @@ -2,7 +2,7 @@ using System; using Android.App; using Android.Content.PM; using Android.OS; -using Avalonia.Android.Platform.Specific; +using Avalonia.Android; using Avalonia.Controls; using Avalonia.Controls.Templates; using Avalonia.Markup.Xaml; @@ -17,36 +17,24 @@ namespace Avalonia.AndroidTestApplication Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance/*, ScreenOrientation = ScreenOrientation.Landscape*/)] - public class MainBaseActivity : AvaloniaActivity + public class MainBaseActivity : Activity { - public MainBaseActivity() : base(typeof (App)) - { - - } - protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); - - App app; - if (Avalonia.Application.Current != null) - app = (App)Avalonia.Application.Current; - else + if (Avalonia.Application.Current == null) { - app = new App(); - AppBuilder.Configure(app) + AppBuilder.Configure() .UseAndroid() - .UseSkia() .SetupWithoutStarting(); } - - app.Run(); + SetContentView(new AvaloniaView(this) { Content = App.CreateSimpleWindow() }); } } public class App : Application { - public void Run() + public override void Initialize() { Styles.Add(new DefaultTheme()); @@ -55,18 +43,14 @@ namespace Avalonia.AndroidTestApplication new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default")); Styles.Add(baseLight); - var wnd = App.CreateSimpleWindow(); - wnd.AttachDevTools(); - Run(wnd); } // This provides a simple UI tree for testing input handling, drawing, etc - public static Window CreateSimpleWindow() + public static ContentControl CreateSimpleWindow() { - Window window = new Window + ContentControl window = new ContentControl() { - Title = "Avalonia Test Application", Background = Brushes.Red, Content = new StackPanel { diff --git a/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj b/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj index fdde5553eb..35c7af454b 100644 --- a/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj +++ b/src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj @@ -89,6 +89,7 @@ + diff --git a/src/Skia/Avalonia.Skia.Android/NativeMethods.cs b/src/Skia/Avalonia.Skia.Android/NativeMethods.cs new file mode 100644 index 0000000000..b9557c00c7 --- /dev/null +++ b/src/Skia/Avalonia.Skia.Android/NativeMethods.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; + +namespace Avalonia.Skia.Android +{ + static class NativeMethods + { + [DllImport("android")] + internal static extern IntPtr ANativeWindow_fromSurface(IntPtr jniEnv, IntPtr handle); + + [DllImport("android")] + internal static extern void ANativeWindow_release(IntPtr window); + [DllImport("android")] + internal static extern void ANativeWindow_unlockAndPost(IntPtr window); + + [DllImport("android")] + internal static extern int ANativeWindow_lock(IntPtr window, out ANativeWindow_Buffer outBuffer, ref ARect inOutDirtyBounds); + public enum AndroidPixelFormat + { + WINDOW_FORMAT_RGBA_8888 = 1, + WINDOW_FORMAT_RGBX_8888 = 2, + WINDOW_FORMAT_RGB_565 = 4, + } + + internal struct ARect + { + public int left; + public int top; + public int right; + public int bottom; + } + + + internal struct ANativeWindow_Buffer + { + // The number of pixels that are show horizontally. + public int width; + + // The number of pixels that are shown vertically. + public int height; + + // The number of *pixels* that a line in the buffer takes in + // memory. This may be >= width. + public int stride; + + // The format of the buffer. One of WINDOW_FORMAT_* + public AndroidPixelFormat format; + + // The actual bits. + public IntPtr bits; + + // Do not touch. + uint reserved1; + uint reserved2; + uint reserved3; + uint reserved4; + uint reserved5; + uint reserved6; + } + } +} \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android/RenderTarget.cs b/src/Skia/Avalonia.Skia.Android/RenderTarget.cs index 03ddf49851..2ee8d5a839 100644 --- a/src/Skia/Avalonia.Skia.Android/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Android/RenderTarget.cs @@ -3,7 +3,9 @@ using Avalonia.Media; using Avalonia.Platform; using SkiaSharp; using Android.Graphics; +using Android.Runtime; using Android.Views; +using Avalonia.Skia.Android; namespace Avalonia.Skia { @@ -27,49 +29,38 @@ namespace Avalonia.Skia internal class WindowRenderTarget : RenderTarget { private readonly SurfaceView _surfaceView; - Bitmap _bitmap; - int Width { get; set; } - int Height { get; set; } + private IntPtr _window; public WindowRenderTarget(SurfaceView surfaceView) { _surfaceView = surfaceView; - FixSize(); } - private void FixSize() + private void PrepareForDraw() { - int width, height; - GetPlatformWindowSize(out width, out height); - if (Width == width && Height == height) - return; - - Width = width; - Height = height; - - if (Surface != null) - { - Surface.Dispose(); - } - - if (_bitmap != null) - { - _bitmap.Dispose(); - } - - _bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888); - Surface = SKSurface.Create(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul, _bitmap.LockPixels(), width * 4); - } - - private void GetPlatformWindowSize(out int w, out int h) - { - w = _surfaceView.Width; - h = _surfaceView.Height; + int width = _surfaceView.Width; + var height = _surfaceView.Height; + + _window = NativeMethods.ANativeWindow_fromSurface(JNIEnv.Handle, _surfaceView.Holder.Surface.Handle); + var buffer = new NativeMethods.ANativeWindow_Buffer(); + var rc = new NativeMethods.ARect() {right = width, bottom = height}; + NativeMethods.ANativeWindow_lock(_window, out buffer, ref rc); + + var colorType = buffer.format == NativeMethods.AndroidPixelFormat.WINDOW_FORMAT_RGB_565 + ? SKColorType.Rgb565 : SKImageInfo.PlatformColorType; + + var stride = buffer.stride * (colorType == SKColorType.Rgb565 ? 2 : 4); + + Surface = SKSurface.Create(buffer.width, buffer.height, colorType, + SKAlphaType.Premul, buffer.bits, stride); + + if (Surface == null) + throw new Exception("Unable to create Skia surface"); } public override DrawingContext CreateDrawingContext() { - FixSize(); + PrepareForDraw(); var canvas = Surface.Canvas; canvas.RestoreToCount(0); @@ -84,23 +75,11 @@ namespace Avalonia.Skia public void Present() { - Canvas canvas = null; - try - { - canvas = _surfaceView.Holder.LockCanvas(null); - _bitmap.UnlockPixels(); - canvas.DrawBitmap(_bitmap, 0, 0, null); - } - catch (Exception) - { - } - finally - { - if (canvas != null) - _surfaceView.Holder.UnlockCanvasAndPost(canvas); - } - - _bitmap.UnlockPixels(); + Surface?.Dispose(); + Surface = null; + NativeMethods.ANativeWindow_unlockAndPost(_window); + NativeMethods.ANativeWindow_release(_window); + _window = IntPtr.Zero; } } } diff --git a/src/Skia/Avalonia.Skia.Android/SkiaView.cs b/src/Skia/Avalonia.Skia.Android/SkiaView.cs index a45a80cf18..f69462f087 100644 --- a/src/Skia/Avalonia.Skia.Android/SkiaView.cs +++ b/src/Skia/Avalonia.Skia.Android/SkiaView.cs @@ -18,12 +18,12 @@ namespace Avalonia.Skia.Android { public abstract class SkiaView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle { - private readonly Activity _context; + private readonly Context _context; bool _invalidateQueued; readonly object _lock = new object(); private readonly Handler _handler; - public SkiaView(Activity context) : base(context) + public SkiaView(Context context) : base(context) { _context = context; Holder.AddCallback(this); From 87de5719253cff9f82701ac0b0f51e16acb516de Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 29 Jan 2017 00:43:22 +0300 Subject: [PATCH 12/15] Use IFramebufferSurface for android. --- Avalonia.sln | 39 +---- .../Avalonia.Android/Avalonia.Android.csproj | 2 + .../SkiaPlatform/AndroidFramebuffer.cs} | 56 +++++-- .../InvalidationAwareSurfaceView.cs} | 6 +- .../Platform/SkiaPlatform/TopLevelImpl.cs | 10 +- src/Skia/Avalonia.Skia.Android.TestApp/App.cs | 7 - .../Avalonia.Skia.Android.TestApp.csproj | 138 ------------------ ...nia.Skia.Android.TestApp.v2.ncrunchproject | 26 ---- .../MainActivity.cs | 78 ---------- .../Properties/AndroidManifest.xml | 5 - .../Properties/AssemblyInfo.cs | 30 ---- .../Resources/Resource.Designer.cs | 114 --------------- .../Resources/drawable/Icon.png | Bin 4147 -> 0 bytes .../Resources/layout/Main.axml | 13 -- .../Resources/values/Strings.xml | 5 - .../AndroidPlatformRenderInterface.cs | 9 +- .../AndroidRenderTarget.cs | 24 --- .../Avalonia.Skia.Android.csproj | 5 - .../Avalonia.Skia.Android/RenderTarget.cs | 85 ----------- .../Avalonia.Skia.Android/SkiaRenderView.cs | 39 ----- .../Avalonia.Skia.iOS.csproj | 1 + .../WindowDrawingContextImpl.cs | 0 .../Avalonia.Skia/Avalonia.Skia.projitems | 1 - 23 files changed, 63 insertions(+), 630 deletions(-) rename src/{Skia/Avalonia.Skia.Android/NativeMethods.cs => Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs} (52%) rename src/{Skia/Avalonia.Skia.Android/SkiaView.cs => Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs} (90%) delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/App.cs delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Resources/drawable/Icon.png delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml delete mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Resources/values/Strings.xml delete mode 100644 src/Skia/Avalonia.Skia.Android/AndroidRenderTarget.cs delete mode 100644 src/Skia/Avalonia.Skia.Android/RenderTarget.cs delete mode 100644 src/Skia/Avalonia.Skia.Android/SkiaRenderView.cs rename src/Skia/{Avalonia.Skia => Avalonia.Skia.iOS}/WindowDrawingContextImpl.cs (100%) diff --git a/Avalonia.sln b/Avalonia.sln index a6fdcbd421..d204e4116b 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26014.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}" EndProject @@ -99,8 +99,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Desktop", "sr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android", "src\Skia\Avalonia.Skia.Android\Avalonia.Skia.Android.csproj", "{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android.TestApp", "src\Skia\Avalonia.Skia.Android.TestApp\Avalonia.Skia.Android.TestApp.csproj", "{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS.TestApp", "src\Skia\Avalonia.Skia.iOS.TestApp\Avalonia.Skia.iOS.TestApp.csproj", "{DA49C5F3-BE95-461C-B999-072128CCF59E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS", "src\Skia\Avalonia.Skia.iOS\Avalonia.Skia.iOS.csproj", "{47BE08A7-5985-410B-9FFC-2264B8EA595F}" @@ -1469,38 +1467,6 @@ Global {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Mono.ActiveCfg = Release|Any CPU {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.ActiveCfg = Release|Any CPU {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.Build.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|Mono.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Mono.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Build.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Deploy.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhone.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Mono.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Build.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Deploy.0 = Release|Any CPU {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone @@ -2359,7 +2325,6 @@ Global {2F59F3D0-748D-4652-B01E-E0D954756308} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} {925DD807-B651-475F-9F7C-CBEB974CE43D} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} {DA49C5F3-BE95-461C-B999-072128CCF59E} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} {47BE08A7-5985-410B-9FFC-2264B8EA595F} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} {7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj index e84146ffb3..0dfab3f518 100644 --- a/src/Android/Avalonia.Android/Avalonia.Android.csproj +++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj @@ -70,6 +70,8 @@ + + diff --git a/src/Skia/Avalonia.Skia.Android/NativeMethods.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs similarity index 52% rename from src/Skia/Avalonia.Skia.Android/NativeMethods.cs rename to src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs index b9557c00c7..982c79560b 100644 --- a/src/Skia/Avalonia.Skia.Android/NativeMethods.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs @@ -1,23 +1,54 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; - -using Android.App; -using Android.Content; -using Android.OS; using Android.Runtime; using Android.Views; -using Android.Widget; +using Avalonia.Controls.Platform.Surfaces; -namespace Avalonia.Skia.Android +namespace Avalonia.Android.Platform.SkiaPlatform { - static class NativeMethods + class AndroidFramebuffer : ILockedFramebuffer { + private IntPtr _window; + + public AndroidFramebuffer(Surface surface) + { + _window = ANativeWindow_fromSurface(JNIEnv.Handle, surface.Handle); + ANativeWindow_Buffer buffer; + var rc = new ARect() + { + right = Width = ANativeWindow_getWidth(_window), + bottom = Height = ANativeWindow_getHeight(_window) + }; + ANativeWindow_lock(_window, out buffer, ref rc); + + Format = buffer.format == AndroidPixelFormat.WINDOW_FORMAT_RGB_565 + ? PixelFormat.Rgb565 : PixelFormat.Rgba8888; + + RowBytes = buffer.stride * (Format == PixelFormat.Rgb565 ? 2 : 4); + Address = buffer.bits; + } + + public void Dispose() + { + ANativeWindow_unlockAndPost(_window); + ANativeWindow_release(_window); + _window = IntPtr.Zero; + Address = IntPtr.Zero; + } + + public IntPtr Address { get; set; } + public int Width { get; } + public int Height { get; } + public int RowBytes { get; } + public Size Dpi { get; } = new Size(96, 96); + public PixelFormat Format { get; } + [DllImport("android")] internal static extern IntPtr ANativeWindow_fromSurface(IntPtr jniEnv, IntPtr handle); - + [DllImport("android")] + internal static extern int ANativeWindow_getWidth(IntPtr window); + [DllImport("android")] + internal static extern int ANativeWindow_getHeight(IntPtr window); [DllImport("android")] internal static extern void ANativeWindow_release(IntPtr window); [DllImport("android")] @@ -39,8 +70,7 @@ namespace Avalonia.Skia.Android public int right; public int bottom; } - - + internal struct ANativeWindow_Buffer { // The number of pixels that are show horizontally. diff --git a/src/Skia/Avalonia.Skia.Android/SkiaView.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs similarity index 90% rename from src/Skia/Avalonia.Skia.Android/SkiaView.cs rename to src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs index f69462f087..2213ebddcc 100644 --- a/src/Skia/Avalonia.Skia.Android/SkiaView.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs @@ -14,16 +14,16 @@ using Android.Widget; using Avalonia.Media; using Avalonia.Platform; -namespace Avalonia.Skia.Android +namespace Avalonia.Android { - public abstract class SkiaView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle + public abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, IPlatformHandle { private readonly Context _context; bool _invalidateQueued; readonly object _lock = new object(); private readonly Handler _handler; - public SkiaView(Context context) : base(context) + public InvalidationAwareSurfaceView(Context context) : base(context) { _context = context; Holder.AddCallback(this); diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 1687432bb3..26d2b0aad9 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -7,14 +7,16 @@ using Avalonia.Android.Platform.Specific.Helpers; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Platform; -using Avalonia.Skia.Android; using System; using System.Collections.Generic; using Avalonia.Controls; +using Avalonia.Controls.Platform.Surfaces; namespace Avalonia.Android.Platform.SkiaPlatform { - class TopLevelImpl : SkiaView, IAndroidView, ITopLevelImpl, ISurfaceHolderCallback + class TopLevelImpl : InvalidationAwareSurfaceView, IAndroidView, ITopLevelImpl, + ISurfaceHolderCallback, IFramebufferPlatformSurface + { protected AndroidKeyboardEventsHelper _keyboardHelper; @@ -183,5 +185,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform { // No window icons for mobile platforms } - } + + ILockedFramebuffer IFramebufferPlatformSurface.Lock()=>new AndroidFramebuffer(Holder.Surface); + } } \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/App.cs b/src/Skia/Avalonia.Skia.Android.TestApp/App.cs deleted file mode 100644 index ca4d36b820..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/App.cs +++ /dev/null @@ -1,7 +0,0 @@ - -namespace Avalonia.Skia.Android.TestApp -{ - public class App : Application - { - } -} diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj b/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj deleted file mode 100644 index 041c8d9ecb..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj +++ /dev/null @@ -1,138 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Properties - Avalonia.Skia.Android.TestApp - Avalonia.Skia.Android.TestApp - 512 - true - Resources\Resource.Designer.cs - Off - False - v4.4 - Properties\AndroidManifest.xml - - - True - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - True - None - False - False - False - armeabi;armeabi-v7a;x86 - Xamarin - False - True - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - False - Full - True - False - False - Xamarin - False - False - False - False - False - armeabi;armeabi-v7a;x86 - - - - - - - - - - - - - - - - - - - - - - - - {7b92af71-6287-4693-9dcb-bd5b6e927e23} - Avalonia.Android - - - {d211e587-d8bc-45b9-95a4-f297c8fa5200} - Avalonia.Animation - - - {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Avalonia.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Avalonia.Controls - - - {4a1abb09-9047-4bd5-a4ad-a055e52c5ee0} - Avalonia.DotNetFrameworkRuntime - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Avalonia.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Avalonia.Interactivity - - - {42472427-4774-4c81-8aff-9f27b8e31721} - Avalonia.Layout - - - {eb582467-6abb-43a1-b052-e981ba910e3a} - Avalonia.Visuals - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Avalonia.Styling - - - {bd43f7c0-396b-4aa1-bad9-dfde54d51298} - Avalonia.Skia.Android - - - - - - - - - \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject b/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject deleted file mode 100644 index e1b4d7cf28..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.v2.ncrunchproject +++ /dev/null @@ -1,26 +0,0 @@ - - true - 1000 - false - false - false - true - false - false - true - false - false - false - true - false - true - true - true - 60000 - - - - AutoDetect - STA - x86 - \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs b/src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs deleted file mode 100644 index 9ac833a559..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Android.App; -using Android.OS; -using Android.Views; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Media; - -namespace Avalonia.Skia.Android.TestApp -{ - [Activity(Label = "Avalonia.Skia.Android.TestApp", MainLauncher = true, Icon = "@drawable/icon")] - public class MainActivity : Activity - { - - protected override void OnCreate(Bundle bundle) - { - base.OnCreate(bundle); - - App app; - if (Avalonia.Application.Current != null) - app = (App)Avalonia.Application.Current; - else - { - app = new App(); - AppBuilder.Configure(app) - .UseAndroid() - .UseSkia() - .SetupWithoutStarting(); - } - - SetContentView(new MainView(this)); - } - - class MainView : SkiaRenderView - { - float _radians = 0; - public MainView(Activity context) : base(context) - { - } - - protected override void OnRender(DrawingContext ctx) - { - ctx.FillRectangle(Brushes.Green, new Rect(0, 0, Width, Height)); - - var rc = new Rect(0, 0, Width/3, Height/3); - using (ctx.PushPostTransform( - Avalonia.Matrix.CreateTranslation(-Width/6, -Width/6)* - Avalonia.Matrix.CreateRotation(_radians)* - Avalonia.Matrix.CreateTranslation(Width/2, Height/2))) - { - ctx.FillRectangle(new LinearGradientBrush() - { - GradientStops = - { - new GradientStop() {Color = Colors.Blue}, - new GradientStop(Colors.Red, 1) - } - }, rc, 5); - } - - - } - - public override bool OnTouchEvent(MotionEvent e) - { - if (e.Action == MotionEventActions.Down) - return true; - if (e.Action == MotionEventActions.Move) - { - _radians = (e.RawY + e.RawY)/100; - Invalidate(); - return true; - } - return base.OnTouchEvent(e); - } - } - } -} - diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml b/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml deleted file mode 100644 index 5af8811830..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs b/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs deleted file mode 100644 index 68efca2668..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Android.App; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Avalonia.Skia.Android.TestApp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Avalonia.Skia.Android.TestApp")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs b/src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs deleted file mode 100644 index 7d9036603f..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs +++ /dev/null @@ -1,114 +0,0 @@ -#pragma warning disable 1591 -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -[assembly: global::Android.Runtime.ResourceDesignerAttribute("Avalonia.Skia.Android.TestApp.Resource", IsApplication=true)] - -namespace Avalonia.Skia.Android.TestApp -{ - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] - public partial class Resource - { - - static Resource() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - public static void UpdateIdValues() - { - global::Avalonia.Android.Resource.String.ApplicationName = global::Avalonia.Skia.Android.TestApp.Resource.String.ApplicationName; - global::Avalonia.Android.Resource.String.Hello = global::Avalonia.Skia.Android.TestApp.Resource.String.Hello; - } - - public partial class Attribute - { - - static Attribute() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Attribute() - { - } - } - - public partial class Drawable - { - - // aapt resource value: 0x7f020000 - public const int Icon = 2130837504; - - static Drawable() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Drawable() - { - } - } - - public partial class Id - { - - // aapt resource value: 0x7f050000 - public const int MyButton = 2131034112; - - static Id() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Id() - { - } - } - - public partial class Layout - { - - // aapt resource value: 0x7f030000 - public const int Main = 2130903040; - - static Layout() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private Layout() - { - } - } - - public partial class String - { - - // aapt resource value: 0x7f040001 - public const int ApplicationName = 2130968577; - - // aapt resource value: 0x7f040000 - public const int Hello = 2130968576; - - static String() - { - global::Android.Runtime.ResourceIdManager.UpdateIdValues(); - } - - private String() - { - } - } - } -} -#pragma warning restore 1591 diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/drawable/Icon.png b/src/Skia/Avalonia.Skia.Android.TestApp/Resources/drawable/Icon.png deleted file mode 100644 index 8074c4c571b8cd19e27f4ee5545df367420686d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4147 zcmV-35X|q1P)OwvMs$Q8_8nISM!^>PxsujeDCl4&hPxrxkp%Qc^^|l zp6LqAcf3zf1H4aA1Gv-O6ha)ktct9Y+VA@N^9i;p0H%6v>ZJZYQ`zEa396z-gi{r_ zDz)D=vgRv62GCVeRjK{15j7V@v6|2nafFX6W7z2j1_T0a zLyT3pGTubf1lB5)32>bl0*BflrA!$|_(WD2)iJIfV}37=ZKAC zSe3boYtQ=;o0i>)RtBvsI#iT{0!oF1VFeW`jDjF2Q4aE?{pGCAd>o8Kg#neIh*AMY zLl{;F!vLiem7s*x0<9FKAd6LoPz3~G32P+F+cuGOJ5gcC@pU_?C2fmix7g2)SUaQO$NS07~H)#fn!Q<}KQWtX}wW`g2>cMld+`7Rxgq zChaey66SG560JhO66zA!;sK1cWa2AG$9k~VQY??6bOmJsw9@3uL*z;WWa7(Nm{^TA zilc?y#N9O3LcTo2c)6d}SQl-v-pE4^#wb=s(RxaE28f3FQW(yp$ulG9{KcQ7r>7mQ zE!HYxUYex~*7IinL+l*>HR*UaD;HkQhkL(5I@UwN%Wz504M^d!ylo>ANvKPF_TvA< zkugG5;F6x}$s~J8cnev->_(Ic7%lGQgUi3n#XVo36lUpcS9s z)ympRr7}@|6WF)Ae;D{owN1;aZSR50al9h~?-WhbtKK%bDd zhML131oi1Bu1&Qb$Cp199LJ#;j5d|FhW8_i4KO1OI>}J^p2DfreMSVGY9aFlr&90t zyI2FvxQiKMFviSQeP$Ixh#70qj5O%I+O_I2t2XHWqmh2!1~tHpN3kA4n=1iHj?`@c<~3q^X6_Q$AqTDjBU`|!y<&lkqL|m5tG(b z8a!z&j^m(|;?SW(l*?tZ*{m2H9d&3jqBtXh>O-5e4Qp-W*a5=2NL&Oi62BUM)>zE3 zbSHb>aU3d@3cGggA`C-PsT9^)oy}%dHCaO~nwOrm5E54=aDg(&HR4S23Oa#-a^=}w%g?ZP-1iq8PSjE8jYaGZu z$I)?YN8he?F9>)2d$G6a*zm0XB*Rf&gZAjq(8l@CUDSY1tB#!i> zW$VfG%#SYSiZ};)>pHA`qlfDTEYQEwN6>NNEp+uxuqx({Fgr zjI@!4xRc?vk^9+~eU|mzH__dCDI=xb{Cd}4bELS9xRaS!*FXMwtMR-RR%SLMh0Cjl zencr8#Su<4(%}$yGVBU-HX{18v=yPH*+%^Vtknc>2A;%-~DrYFx^3XfuVgvZ{#1tA== zm3>IzAM2{3Iv_d1XG{P6^tN3|PkJMnjs&CWN7%7_CmjoVakUhsa&dMv==2~^ri?&x zVdv*rnfVyM+I1^Kg*S=23mR@+0T9BWFZUu~@toA8d)fw6be=`Yb6DSX6D?jB%2YT~ z*aHjtIOozfMhA!Jd*?u5_n!SnX>vX`=Ti-1HA4RiE>eI3vTn zz+>Ccf0HX6Ans-ebOB>RJST-Cyr#4XAk+mAlJgdQnoE{^iIN)OcYFSpgJUmXtl@tT z-^ZuUeSj5hSFrQwqX>~EtZ*{>Gi8Bu9_|o06oNtaXP?E936!a@DsvS*tsB@fa6kEA z5GkjwmH?EgpiG&itsB_Tb1NxtFnvxh_s@9KYX1Sttf?AlI~)z zT=6Y7ulx=}<8Scr_UqU-_z)5gPo%050PsbM*ZLno;_-ow&k?FZJtYmb2hPA$LkP)8 z=^d0Q6PImh6Y|QT?{grxj)S=uBKvY2EQUbm@ns9^yKiP~$DcD)c$5Em`zDSScH%iH zVov&m=cMo`1tYwA=!a}vb_ef_{)Q2?FUqn>BR$6phXQRv^1%=YfyE-F$AR4Q?9D!f zCzB^^#td~4u&l~l#rp2QLfe3+_ub9@+|x+m;=2(sQ`s%gO|j$XBb>A7Q(UydipiMw%igcweV#Cr~SP);q>w`bxts_4} znKHg?X==JDkQl3Y>Ckt%`s{n?Nq-1Fw5~%Mq$CAsi-`yu_bKm zxs#QdE7&vgJD%M84f4SNzSDv)S|V?|$!d5a#lhT5>>YWE4NGqa9-fbmV$=)@k&32kdEYetna>=j@0>V8+wRsL;po!3ivVwh<9tn z2S<1u9DAAQ>x1Sn=fk`)At|quvleV($B|#Kap_lB-F^*yV=wZ{9baUu(uXfokr95^ zA*!*W=5a>$2Ps`-F^+qRQT^{*cN>vipT*4!r#p%{(#I7s z0NN94*q?ib$KJjfDI_sjHNdmEVp5wB&j54O#VoFqBwy)gfA$%)4d_X4q${L9Xom2R3xy&ZBSNgt4a1d7K^CDWa9r zVb-_52m}Vp)`9;ZSKd#|U4ZYj5}Gp49{4utST|=c`~(#>KHF6}CCov1iHYw zt{bWo)A@yF2$~c(nR$rSAaFQ$(Wh{vkG1AlutDMw=mM`C`T=X&|Ad9fb5Od}ROt1z zOpczHqrb4Jo^rSCiW#&o(m7jFamnrsTpQb;*h4o8r#$aZ}2RaT-x2u^^ z%u@YyIv$U^u~@9(XGbSwU@fk6SikH>j+D1jQrYTKGJpW%vUT{!d}7THI5&Sa?~MKy zS0-mvMl+BOcroEJ@hN!2H_?coTEJ5Q<;Nd?yx;eIj4{$$E2?YUO|NtNPJ-PdDf;s} zab;}Mz0kbOI}5*w@3gROcnl#5)wQnEhDBfn!Xhy`u>C}*E~vWpO^HS)FC>8^umI=+ z&H;LW6w#;EF`}vQd_9Muru`KnQVPI9U?(sD)&Dg-0j3#(!fNKVZ_GoYH{la~d*1Yh$TI-TL>mI4vpNb@sU2=IZ8vL%AXUx0 zz{K0|nK(yizLHaeW#ZhRfQXoK^}1$=$#1{Yn002ovPDHLkV1n#w+^+xt diff --git a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml b/src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml deleted file mode 100644 index 98be1643ef..0000000000 --- a/src/Skia/Avalonia.Skia.Android.TestApp/Resources/layout/Main.axml +++ /dev/null @@ -1,13 +0,0 @@ - - -