Browse Source

Merge branch 'master' into 9612-duplicate-setters

pull/10113/head
Max Katz 3 years ago
committed by GitHub
parent
commit
443f7c1f43
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs
  2. 46
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
  3. 1
      src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs
  4. 8
      src/Avalonia.Base/Platform/SystemNavigationManagerImpl.cs
  5. 4
      src/Avalonia.Controls/Button.cs
  6. 2
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  7. 2
      src/Avalonia.Controls/NativeControlHost.cs
  8. 3
      src/Avalonia.Controls/NativeMenu.Export.cs
  9. 6
      src/Avalonia.Controls/Platform/INativeControlHostImpl.cs
  10. 2
      src/Avalonia.Controls/Platform/ITopLevelImpl.cs
  11. 11
      src/Avalonia.Controls/Platform/ITopLevelImplWithStorageProvider.cs
  12. 13
      src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs
  13. 6
      src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs
  14. 9
      src/Avalonia.Controls/TopLevel.cs
  15. 14
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  16. 1
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  17. 11
      src/Avalonia.Headless/HeadlessWindowImpl.cs
  18. 18
      src/Avalonia.Native/WindowImpl.cs
  19. 21
      src/Avalonia.Native/WindowImplBase.cs
  20. 45
      src/Avalonia.X11/X11Window.cs
  21. 4
      src/Browser/Avalonia.Browser/BrowserSystemNavigationManager.cs
  22. 36
      src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs
  23. 1
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  24. 2
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  25. 32
      src/Windows/Avalonia.Win32/WindowImpl.cs
  26. 31
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  27. 1
      tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs
  28. 1
      tests/Avalonia.LeakTests/ControlTests.cs
  29. 4
      tests/Avalonia.UnitTests/CompositorTestServices.cs
  30. 3
      tests/Avalonia.UnitTests/MockWindowingPlatform.cs

4
src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs

@ -4,11 +4,11 @@ using Avalonia.Platform;
namespace Avalonia.Android.Platform namespace Avalonia.Android.Platform
{ {
internal class AndroidSystemNavigationManager : ISystemNavigationManager internal class AndroidSystemNavigationManagerImpl : ISystemNavigationManagerImpl
{ {
public event EventHandler<RoutedEventArgs> BackRequested; public event EventHandler<RoutedEventArgs> BackRequested;
public AndroidSystemNavigationManager(IActivityNavigationService? navigationService) public AndroidSystemNavigationManagerImpl(IActivityNavigationService? navigationService)
{ {
if(navigationService != null) if(navigationService != null)
{ {

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

@ -31,9 +31,7 @@ using Android.Graphics.Drawables;
namespace Avalonia.Android.Platform.SkiaPlatform namespace Avalonia.Android.Platform.SkiaPlatform
{ {
class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo, class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider,
ITopLevelWithSystemNavigationManager
{ {
private readonly IGlPlatformSurface _gl; private readonly IGlPlatformSurface _gl;
private readonly IFramebufferPlatformSurface _framebuffer; private readonly IFramebufferPlatformSurface _framebuffer;
@ -41,6 +39,9 @@ namespace Avalonia.Android.Platform.SkiaPlatform
private readonly AndroidKeyboardEventsHelper<TopLevelImpl> _keyboardHelper; private readonly AndroidKeyboardEventsHelper<TopLevelImpl> _keyboardHelper;
private readonly AndroidMotionEventsHelper _pointerHelper; private readonly AndroidMotionEventsHelper _pointerHelper;
private readonly AndroidInputMethod<ViewImpl> _textInputMethod; private readonly AndroidInputMethod<ViewImpl> _textInputMethod;
private readonly INativeControlHostImpl _nativeControlHost;
private readonly IStorageProvider _storageProvider;
private readonly ISystemNavigationManagerImpl _systemNavigationManager;
private ViewImpl _view; private ViewImpl _view;
public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false) public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false)
@ -57,10 +58,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels, MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels,
_view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling); _view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling);
NativeControlHost = new AndroidNativeControlHostImpl(avaloniaView); _nativeControlHost = new AndroidNativeControlHostImpl(avaloniaView);
StorageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context); _storageProvider = new AndroidStorageProvider((Activity)avaloniaView.Context);
SystemNavigationManager = new AndroidSystemNavigationManager(avaloniaView.Context as IActivityNavigationService); _systemNavigationManager = new AndroidSystemNavigationManagerImpl(avaloniaView.Context as IActivityNavigationService);
} }
public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) => public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) =>
@ -294,14 +295,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public double Scaling => RenderScaling; public double Scaling => RenderScaling;
public ITextInputMethodImpl TextInputMethod => _textInputMethod;
public INativeControlHostImpl NativeControlHost { get; }
public IStorageProvider StorageProvider { get; }
public ISystemNavigationManager SystemNavigationManager { get; }
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{ {
if (TransparencyLevel != transparencyLevel) if (TransparencyLevel != transparencyLevel)
@ -386,6 +379,31 @@ namespace Avalonia.Android.Platform.SkiaPlatform
} }
} }
} }
public virtual object TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
if (featureType == typeof(ITextInputMethodImpl))
{
return _textInputMethod;
}
if (featureType == typeof(ISystemNavigationManagerImpl))
{
return _systemNavigationManager;
}
if (featureType == typeof(INativeControlHostImpl))
{
return _nativeControlHost;
}
return null;
}
} }
internal class AvaloniaInputConnection : BaseInputConnection internal class AvaloniaInputConnection : BaseInputConnection

1
src/Avalonia.Base/Platform/IOptionalFeatureProvider.cs

@ -23,5 +23,4 @@ public static class OptionalFeatureProviderExtensions
rv = provider.TryGetFeature<T>(); rv = provider.TryGetFeature<T>();
return rv != null; return rv != null;
} }
} }

8
src/Avalonia.Base/Platform/SystemNavigationManager.cs → src/Avalonia.Base/Platform/SystemNavigationManagerImpl.cs

@ -5,13 +5,7 @@ using Avalonia.Metadata;
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
[Unstable] [Unstable]
public interface ITopLevelWithSystemNavigationManager public interface ISystemNavigationManagerImpl
{
ISystemNavigationManager SystemNavigationManager { get; }
}
[Unstable]
public interface ISystemNavigationManager
{ {
public event EventHandler<RoutedEventArgs>? BackRequested; public event EventHandler<RoutedEventArgs>? BackRequested;
} }

4
src/Avalonia.Controls/Button.cs

@ -394,10 +394,10 @@ namespace Avalonia.Controls
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{ {
IsPressed = true; IsPressed = true;
e.Handled = true;
if (ClickMode == ClickMode.Press) if (ClickMode == ClickMode.Press)
{ {
e.Handled = true;
OnClick(); OnClick();
} }
} }
@ -411,11 +411,11 @@ namespace Avalonia.Controls
if (IsPressed && e.InitialPressMouseButton == MouseButton.Left) if (IsPressed && e.InitialPressMouseButton == MouseButton.Left)
{ {
IsPressed = false; IsPressed = false;
e.Handled = true;
if (ClickMode == ClickMode.Release && if (ClickMode == ClickMode.Release &&
this.GetVisualsAt(e.GetPosition(this)).Any(c => this == c || this.IsVisualAncestorOf(c))) this.GetVisualsAt(e.GetPosition(this)).Any(c => this == c || this.IsVisualAncestorOf(c)))
{ {
e.Handled = true;
OnClick(); OnClick();
} }
} }

2
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -94,5 +94,7 @@ namespace Avalonia.Controls.Embedding.Offscreen
public WindowTransparencyLevel TransparencyLevel { get; private set; } public WindowTransparencyLevel TransparencyLevel { get; private set; }
public IPopupImpl? CreatePopup() => null; public IPopupImpl? CreatePopup() => null;
public virtual object? TryGetFeature(Type featureType) => null;
} }
} }

2
src/Avalonia.Controls/NativeControlHost.cs

@ -58,7 +58,7 @@ namespace Avalonia.Controls
private void UpdateHost() private void UpdateHost()
{ {
_queuedForMoveResize = false; _queuedForMoveResize = false;
_currentHost = (_currentRoot?.PlatformImpl as ITopLevelImplWithNativeControlHost)?.NativeControlHost; _currentHost = _currentRoot?.PlatformImpl?.TryGetFeature<INativeControlHostImpl>();
if (_currentHost != null) if (_currentHost != null)
{ {

3
src/Avalonia.Controls/NativeMenu.Export.cs

@ -1,6 +1,7 @@
using System; using System;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
using Avalonia.Reactive; using Avalonia.Reactive;
using Avalonia.Platform;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -21,7 +22,7 @@ namespace Avalonia.Controls
public NativeMenuInfo(TopLevel target) public NativeMenuInfo(TopLevel target)
{ {
Exporter = (target.PlatformImpl as ITopLevelImplWithNativeMenuExporter)?.NativeMenuExporter; Exporter = target.PlatformImpl?.TryGetFeature<ITopLevelNativeMenuExporter>();
if (Exporter != null) if (Exporter != null)
{ {
Exporter.OnIsNativeMenuExportedChanged += delegate Exporter.OnIsNativeMenuExportedChanged += delegate

6
src/Avalonia.Controls/Platform/INativeControlHostImpl.cs

@ -29,10 +29,4 @@ namespace Avalonia.Controls.Platform
void HideWithSize(Size size); void HideWithSize(Size size);
void ShowInBounds(Rect rect); void ShowInBounds(Rect rect);
} }
[Unstable]
public interface ITopLevelImplWithNativeControlHost
{
INativeControlHostImpl? NativeControlHost { get; }
}
} }

2
src/Avalonia.Controls/Platform/ITopLevelImpl.cs

@ -51,7 +51,7 @@ namespace Avalonia.Platform
/// <see cref="IPopupImpl"/>. /// <see cref="IPopupImpl"/>.
/// </remarks> /// </remarks>
[Unstable] [Unstable]
public interface ITopLevelImpl : IDisposable public interface ITopLevelImpl : IOptionalFeatureProvider, IDisposable
{ {
/// <summary> /// <summary>
/// Gets the client size of the toplevel. /// Gets the client size of the toplevel.

11
src/Avalonia.Controls/Platform/ITopLevelImplWithStorageProvider.cs

@ -1,11 +0,0 @@
using Avalonia.Metadata;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
namespace Avalonia.Controls.Platform;
[Unstable]
public interface ITopLevelImplWithStorageProvider : ITopLevelImpl
{
public IStorageProvider StorageProvider { get; }
}

13
src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs

@ -1,13 +0,0 @@
using Avalonia.Input;
using Avalonia.Input.TextInput;
using Avalonia.Metadata;
using Avalonia.Platform;
namespace Avalonia.Controls.Platform
{
[Unstable]
public interface ITopLevelImplWithTextInputMethod : ITopLevelImpl
{
public ITextInputMethodImpl? TextInputMethod { get; }
}
}

6
src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs

@ -23,10 +23,4 @@ namespace Avalonia.Controls.Platform
{ {
INativeMenuExporter? NativeMenuExporter { get; } INativeMenuExporter? NativeMenuExporter { get; }
} }
[Unstable]
public interface ITopLevelImplWithNativeMenuExporter : ITopLevelImpl
{
ITopLevelNativeMenuExporter? NativeMenuExporter { get; }
}
} }

9
src/Avalonia.Controls/TopLevel.cs

@ -216,9 +216,9 @@ namespace Avalonia.Controls
_pointerOverPreProcessor = new PointerOverPreProcessor(this); _pointerOverPreProcessor = new PointerOverPreProcessor(this);
_pointerOverPreProcessorSubscription = _inputManager?.PreProcess.Subscribe(_pointerOverPreProcessor); _pointerOverPreProcessorSubscription = _inputManager?.PreProcess.Subscribe(_pointerOverPreProcessor);
if(impl is ITopLevelWithSystemNavigationManager topLevelWithSystemNavigation) if(impl.TryGetFeature<ISystemNavigationManagerImpl>() is {} systemNavigationManager)
{ {
topLevelWithSystemNavigation.SystemNavigationManager.BackRequested += (s, e) => systemNavigationManager.BackRequested += (s, e) =>
{ {
e.RoutedEvent = BackRequestedEvent; e.RoutedEvent = BackRequestedEvent;
RaiseEvent(e); RaiseEvent(e);
@ -382,7 +382,7 @@ namespace Avalonia.Controls
public IStorageProvider StorageProvider => _storageProvider public IStorageProvider StorageProvider => _storageProvider
??= AvaloniaLocator.Current.GetService<IStorageProviderFactory>()?.CreateProvider(this) ??= AvaloniaLocator.Current.GetService<IStorageProviderFactory>()?.CreateProvider(this)
?? (PlatformImpl as ITopLevelImplWithStorageProvider)?.StorageProvider ?? PlatformImpl?.TryGetFeature<IStorageProvider>()
?? throw new InvalidOperationException("StorageProvider platform implementation is not available."); ?? throw new InvalidOperationException("StorageProvider platform implementation is not available.");
/// <inheritdoc/> /// <inheritdoc/>
@ -616,7 +616,6 @@ namespace Avalonia.Controls
// Do nothing becuase TopLevel should't apply MirrorTransform on himself. // Do nothing becuase TopLevel should't apply MirrorTransform on himself.
} }
ITextInputMethodImpl? ITextInputMethodRoot.InputMethod => ITextInputMethodImpl? ITextInputMethodRoot.InputMethod => PlatformImpl?.TryGetFeature<ITextInputMethodImpl>();
(PlatformImpl as ITopLevelImplWithTextInputMethod)?.TextInputMethod;
} }
} }

14
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -11,7 +11,7 @@ using Avalonia.Threading;
namespace Avalonia.DesignerSupport.Remote namespace Avalonia.DesignerSupport.Remote
{ {
class PreviewerWindowImpl : RemoteServerTopLevelImpl, IWindowImpl, ITopLevelImplWithStorageProvider class PreviewerWindowImpl : RemoteServerTopLevelImpl, IWindowImpl
{ {
private readonly IAvaloniaRemoteTransportConnection _transport; private readonly IAvaloniaRemoteTransportConnection _transport;
@ -92,8 +92,16 @@ namespace Avalonia.DesignerSupport.Remote
public bool NeedsManagedDecorations => false; public bool NeedsManagedDecorations => false;
public IStorageProvider StorageProvider => new NoopStorageProvider(); public override object TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
{
return new NoopStorageProvider();
}
return base.TryGetFeature(featureType);
}
public void Activate() public void Activate()
{ {
} }

1
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -194,6 +194,7 @@ namespace Avalonia.DesignerSupport.Remote
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { } public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType) => null;
} }
class ClipboardStub : IClipboard class ClipboardStub : IClipboard

11
src/Avalonia.Headless/HeadlessWindowImpl.cs

@ -18,7 +18,7 @@ using Avalonia.Utilities;
namespace Avalonia.Headless namespace Avalonia.Headless
{ {
class HeadlessWindowImpl : IWindowImpl, IPopupImpl, IFramebufferPlatformSurface, IHeadlessWindow, ITopLevelImplWithStorageProvider class HeadlessWindowImpl : IWindowImpl, IPopupImpl, IFramebufferPlatformSurface, IHeadlessWindow
{ {
private IKeyboardDevice _keyboard; private IKeyboardDevice _keyboard;
private Stopwatch _st = Stopwatch.StartNew(); private Stopwatch _st = Stopwatch.StartNew();
@ -247,8 +247,15 @@ namespace Avalonia.Headless
public Action LostFocus { get; set; } public Action LostFocus { get; set; }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
{
return new NoopStorageProvider();
}
public IStorageProvider StorageProvider => new NoopStorageProvider(); return null;
}
void IHeadlessWindow.KeyPress(Key key, RawInputModifiers modifiers) void IHeadlessWindow.KeyPress(Key key, RawInputModifiers modifiers)
{ {

18
src/Avalonia.Native/WindowImpl.cs

@ -11,14 +11,14 @@ using Avalonia.Platform.Interop;
namespace Avalonia.Native namespace Avalonia.Native
{ {
internal class WindowImpl : WindowBaseImpl, IWindowImpl, ITopLevelImplWithNativeMenuExporter internal class WindowImpl : WindowBaseImpl, IWindowImpl
{ {
private readonly AvaloniaNativePlatformOptions _opts; private readonly AvaloniaNativePlatformOptions _opts;
private readonly AvaloniaNativeGlPlatformGraphics _glFeature; private readonly AvaloniaNativeGlPlatformGraphics _glFeature;
IAvnWindow _native; IAvnWindow _native;
private double _extendTitleBarHeight = -1; private double _extendTitleBarHeight = -1;
private DoubleClickHelper _doubleClickHelper; private DoubleClickHelper _doubleClickHelper;
private readonly ITopLevelNativeMenuExporter _nativeMenuExporter;
internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts, internal WindowImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
AvaloniaNativeGlPlatformGraphics glFeature) : base(factory, opts, glFeature) AvaloniaNativeGlPlatformGraphics glFeature) : base(factory, opts, glFeature)
@ -32,7 +32,7 @@ namespace Avalonia.Native
Init(_native = factory.CreateWindow(e, glFeature.SharedContext.Context), factory.CreateScreens()); Init(_native = factory.CreateWindow(e, glFeature.SharedContext.Context), factory.CreateScreens());
} }
NativeMenuExporter = new AvaloniaNativeMenuExporter(_native, factory); _nativeMenuExporter = new AvaloniaNativeMenuExporter(_native, factory);
} }
class WindowEvents : WindowBaseEvents, IAvnWindowEvents class WindowEvents : WindowBaseEvents, IAvnWindowEvents
@ -209,8 +209,6 @@ namespace Avalonia.Native
public Func<WindowCloseReason, bool> Closing { get; set; } public Func<WindowCloseReason, bool> Closing { get; set; }
public ITopLevelNativeMenuExporter NativeMenuExporter { get; }
public void Move(PixelPoint point) => Position = point; public void Move(PixelPoint point) => Position = point;
public override IPopupImpl CreatePopup() => public override IPopupImpl CreatePopup() =>
@ -227,5 +225,15 @@ namespace Avalonia.Native
{ {
_native.SetEnabled(enable.AsComBool()); _native.SetEnabled(enable.AsComBool());
} }
public override object TryGetFeature(Type featureType)
{
if (featureType == typeof(ITopLevelNativeMenuExporter))
{
return _nativeMenuExporter;
}
return base.TryGetFeature(featureType);
}
} }
} }

21
src/Avalonia.Native/WindowImplBase.cs

@ -47,7 +47,7 @@ namespace Avalonia.Native
} }
internal abstract class WindowBaseImpl : IWindowBaseImpl, internal abstract class WindowBaseImpl : IWindowBaseImpl,
IFramebufferPlatformSurface, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider IFramebufferPlatformSurface
{ {
protected readonly IAvaloniaNativeFactory _factory; protected readonly IAvaloniaNativeFactory _factory;
protected IInputRoot _inputRoot; protected IInputRoot _inputRoot;
@ -62,6 +62,7 @@ namespace Avalonia.Native
private double _savedScaling; private double _savedScaling;
private GlPlatformSurface _glSurface; private GlPlatformSurface _glSurface;
private NativeControlHostImpl _nativeControlHost; private NativeControlHostImpl _nativeControlHost;
private IStorageProvider _storageProvider;
internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts, internal WindowBaseImpl(IAvaloniaNativeFactory factory, AvaloniaNativePlatformOptions opts,
AvaloniaNativeGlPlatformGraphics glFeature) AvaloniaNativeGlPlatformGraphics glFeature)
@ -72,7 +73,6 @@ namespace Avalonia.Native
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>(); _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
_mouse = new MouseDevice(); _mouse = new MouseDevice();
_cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>(); _cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>();
StorageProvider = new SystemDialogs(this, _factory.CreateSystemDialogs());
} }
protected void Init(IAvnWindowBase window, IAvnScreens screens) protected void Init(IAvnWindowBase window, IAvnScreens screens)
@ -87,6 +87,7 @@ namespace Avalonia.Native
_savedLogicalSize = ClientSize; _savedLogicalSize = ClientSize;
_savedScaling = RenderScaling; _savedScaling = RenderScaling;
_nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost()); _nativeControlHost = new NativeControlHostImpl(_native.CreateNativeControlHost());
_storageProvider = new SystemDialogs(this, _factory.CreateSystemDialogs());
var monitor = Screen.AllScreens.OrderBy(x => x.Scaling) var monitor = Screen.AllScreens.OrderBy(x => x.Scaling)
.FirstOrDefault(m => m.Bounds.Contains(Position)); .FirstOrDefault(m => m.Bounds.Contains(Position));
@ -508,9 +509,21 @@ namespace Avalonia.Native
} }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0, 0); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0, 0);
public virtual object TryGetFeature(Type featureType)
{
if (featureType == typeof(INativeControlHostImpl))
{
return _nativeControlHost;
}
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
public IPlatformHandle Handle { get; private set; } return null;
}
public IStorageProvider StorageProvider { get; } public IPlatformHandle Handle { get; private set; }
} }
} }

45
src/Avalonia.X11/X11Window.cs

@ -27,11 +27,7 @@ using static Avalonia.X11.XLib;
// ReSharper disable StringLiteralTypo // ReSharper disable StringLiteralTypo
namespace Avalonia.X11 namespace Avalonia.X11
{ {
unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client, unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
ITopLevelImplWithNativeMenuExporter,
ITopLevelImplWithNativeControlHost,
ITopLevelImplWithTextInputMethod,
ITopLevelImplWithStorageProvider
{ {
private readonly AvaloniaX11Platform _platform; private readonly AvaloniaX11Platform _platform;
private readonly bool _popup; private readonly bool _popup;
@ -43,6 +39,9 @@ namespace Avalonia.X11
private readonly MouseDevice _mouse; private readonly MouseDevice _mouse;
private readonly TouchDevice _touch; private readonly TouchDevice _touch;
private readonly IKeyboardDevice _keyboard; private readonly IKeyboardDevice _keyboard;
private readonly ITopLevelNativeMenuExporter _nativeMenuExporter;
private readonly IStorageProvider _storageProvider;
private readonly X11NativeControlHost _nativeControlHost;
private PixelPoint? _position; private PixelPoint? _position;
private PixelSize _realSize; private PixelSize _realSize;
private IntPtr _handle; private IntPtr _handle;
@ -199,8 +198,8 @@ namespace Avalonia.X11
if(_popup) if(_popup)
PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(popupParent, MoveResize)); PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(popupParent, MoveResize));
if (platform.Options.UseDBusMenu) if (platform.Options.UseDBusMenu)
NativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle); _nativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle);
NativeControlHost = new X11NativeControlHost(_platform, this); _nativeControlHost = new X11NativeControlHost(_platform, this);
InitializeIme(); InitializeIme();
XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32, XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32,
@ -213,7 +212,7 @@ namespace Avalonia.X11
_x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1); _x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1);
} }
StorageProvider = new CompositeStorageProvider(new Func<Task<IStorageProvider>>[] _storageProvider = new CompositeStorageProvider(new Func<Task<IStorageProvider>>[]
{ {
() => _platform.Options.UseDBusFilePicker ? DBusSystemDialog.TryCreate(Handle) : Task.FromResult<IStorageProvider>(null), () => _platform.Options.UseDBusFilePicker ? DBusSystemDialog.TryCreate(Handle) : Task.FromResult<IStorageProvider>(null),
() => GtkSystemDialog.TryCreate(this), () => GtkSystemDialog.TryCreate(this),
@ -796,6 +795,31 @@ namespace Avalonia.X11
Cleanup(); Cleanup();
} }
public virtual object TryGetFeature(Type featureType)
{
if (featureType == typeof(ITopLevelNativeMenuExporter))
{
return _nativeMenuExporter;
}
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
if (featureType == typeof(ITextInputMethodImpl))
{
return _ime;
}
if (featureType == typeof(INativeControlHostImpl))
{
return _nativeControlHost;
}
return null;
}
void Cleanup() void Cleanup()
{ {
if (_rawEventGrouper != null) if (_rawEventGrouper != null)
@ -1195,9 +1219,6 @@ namespace Avalonia.X11
} }
public IPopupPositioner PopupPositioner { get; } public IPopupPositioner PopupPositioner { get; }
public ITopLevelNativeMenuExporter NativeMenuExporter { get; }
public INativeControlHostImpl NativeControlHost { get; }
public ITextInputMethodImpl TextInputMethod => _ime;
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) => public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) =>
_transparencyHelper?.SetTransparencyRequest(transparencyLevel); _transparencyHelper?.SetTransparencyRequest(transparencyLevel);
@ -1215,8 +1236,6 @@ namespace Avalonia.X11
public bool NeedsManagedDecorations => false; public bool NeedsManagedDecorations => false;
public IStorageProvider StorageProvider { get; }
public class SurfacePlatformHandle : IPlatformNativeSurfaceHandle public class SurfacePlatformHandle : IPlatformNativeSurfaceHandle
{ {
private readonly X11Window _owner; private readonly X11Window _owner;

4
src/Browser/Avalonia.Browser/BrowserSystemNavigationManager.cs

@ -5,11 +5,11 @@ using Avalonia.Platform;
namespace Avalonia.Browser namespace Avalonia.Browser
{ {
internal class BrowserSystemNavigationManager : ISystemNavigationManager internal class BrowserSystemNavigationManagerImpl : ISystemNavigationManagerImpl
{ {
public event EventHandler<RoutedEventArgs>? BackRequested; public event EventHandler<RoutedEventArgs>? BackRequested;
public BrowserSystemNavigationManager() public BrowserSystemNavigationManagerImpl()
{ {
NavigationHelper.AddBackHandler(() => NavigationHelper.AddBackHandler(() =>
{ {

36
src/Browser/Avalonia.Browser/BrowserTopLevelImpl.cs

@ -19,8 +19,7 @@ using Avalonia.Rendering.Composition;
namespace Avalonia.Browser namespace Avalonia.Browser
{ {
internal class BrowserTopLevelImpl : ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, ITopLevelImplWithStorageProvider, internal class BrowserTopLevelImpl : ITopLevelImpl
ITopLevelWithSystemNavigationManager
{ {
private Size _clientSize; private Size _clientSize;
private IInputRoot? _inputRoot; private IInputRoot? _inputRoot;
@ -29,6 +28,9 @@ namespace Avalonia.Browser
private readonly TouchDevice _touchDevice; private readonly TouchDevice _touchDevice;
private readonly PenDevice _penDevice; private readonly PenDevice _penDevice;
private string _currentCursor = CssCursor.Default; private string _currentCursor = CssCursor.Default;
private readonly INativeControlHostImpl _nativeControlHost;
private readonly IStorageProvider _storageProvider;
private readonly ISystemNavigationManagerImpl _systemNavigationManager;
public BrowserTopLevelImpl(AvaloniaView avaloniaView) public BrowserTopLevelImpl(AvaloniaView avaloniaView)
{ {
@ -38,7 +40,9 @@ namespace Avalonia.Browser
AcrylicCompensationLevels = new AcrylicPlatformCompensationLevels(1, 1, 1); AcrylicCompensationLevels = new AcrylicPlatformCompensationLevels(1, 1, 1);
_touchDevice = new TouchDevice(); _touchDevice = new TouchDevice();
_penDevice = new PenDevice(); _penDevice = new PenDevice();
NativeControlHost = _avaloniaView.GetNativeControlHostImpl(); _nativeControlHost = _avaloniaView.GetNativeControlHostImpl();
_storageProvider = new BrowserStorageProvider();
_systemNavigationManager = new BrowserSystemNavigationManagerImpl();
} }
public ulong Timestamp => (ulong)_sw.ElapsedMilliseconds; public ulong Timestamp => (ulong)_sw.ElapsedMilliseconds;
@ -236,11 +240,29 @@ namespace Avalonia.Browser
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; }
public ITextInputMethodImpl TextInputMethod => _avaloniaView; public object? TryGetFeature(Type featureType)
{
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
public INativeControlHostImpl? NativeControlHost { get; } if (featureType == typeof(ITextInputMethodImpl))
public IStorageProvider StorageProvider { get; } = new BrowserStorageProvider(); {
return _avaloniaView;
}
public ISystemNavigationManager SystemNavigationManager { get; } = new BrowserSystemNavigationManager(); if (featureType == typeof(ISystemNavigationManagerImpl))
{
return _systemNavigationManager;
}
if (featureType == typeof(INativeControlHostImpl))
{
return _nativeControlHost;
}
return null;
}
} }
} }

1
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@ -77,5 +77,6 @@ namespace Avalonia.LinuxFramebuffer
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { } public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType) => null;
} }
} }

2
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -261,5 +261,7 @@ namespace Avalonia.Win32.Interop.Wpf
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { } public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1); public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType) => null;
} }
} }

32
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -35,10 +35,7 @@ namespace Avalonia.Win32
/// Window implementation for Win32 platform. /// Window implementation for Win32 platform.
/// </summary> /// </summary>
[Unstable] [Unstable]
public partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo, public partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
ITopLevelImplWithNativeControlHost,
ITopLevelImplWithTextInputMethod,
ITopLevelImplWithStorageProvider
{ {
private static readonly List<WindowImpl> s_instances = new List<WindowImpl>(); private static readonly List<WindowImpl> s_instances = new List<WindowImpl>();
@ -83,6 +80,7 @@ namespace Avalonia.Win32
private readonly bool _wmPointerEnabled; private readonly bool _wmPointerEnabled;
private Win32NativeControlHost _nativeControlHost; private Win32NativeControlHost _nativeControlHost;
private IStorageProvider _storageProvider;
private WndProc _wndProcDelegate; private WndProc _wndProcDelegate;
private string _className; private string _className;
private IntPtr _hwnd; private IntPtr _hwnd;
@ -183,7 +181,7 @@ namespace Avalonia.Win32
} }
Screen = new ScreenImpl(); Screen = new ScreenImpl();
StorageProvider = new Win32StorageProvider(this); _storageProvider = new Win32StorageProvider(this);
_nativeControlHost = new Win32NativeControlHost(this, _isUsingComposition); _nativeControlHost = new Win32NativeControlHost(this, _isUsingComposition);
s_instances.Add(this); s_instances.Add(this);
@ -322,6 +320,26 @@ namespace Avalonia.Win32
private bool IsMouseInPointerEnabled => _wmPointerEnabled && IsMouseInPointerEnabled(); private bool IsMouseInPointerEnabled => _wmPointerEnabled && IsMouseInPointerEnabled();
public object TryGetFeature(Type featureType)
{
if (featureType == typeof(ITextInputMethodImpl))
{
return Imm32InputMethod.Current;
}
if (featureType == typeof(INativeControlHostImpl))
{
return _nativeControlHost;
}
if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
return null;
}
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel)
{ {
TransparencyLevel = EnableBlur(transparencyLevel); TransparencyLevel = EnableBlur(transparencyLevel);
@ -1465,10 +1483,6 @@ namespace Avalonia.Win32
public void Dispose() => _owner._resizeReason = _restore; public void Dispose() => _owner._resizeReason = _restore;
} }
public ITextInputMethodImpl TextInputMethod => Imm32InputMethod.Current;
public IStorageProvider StorageProvider { get; }
private class WindowImplPlatformHandle : IPlatformNativeSurfaceHandle private class WindowImplPlatformHandle : IPlatformNativeSurfaceHandle
{ {
private readonly WindowImpl _owner; private readonly WindowImpl _owner;

31
src/iOS/Avalonia.iOS/AvaloniaView.cs

@ -68,17 +68,18 @@ namespace Avalonia.iOS
settings?.TraitCollectionDidChange(); settings?.TraitCollectionDidChange();
} }
internal class TopLevelImpl : ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost, internal class TopLevelImpl : ITopLevelImpl
ITopLevelImplWithStorageProvider
{ {
private readonly AvaloniaView _view; private readonly AvaloniaView _view;
private readonly INativeControlHostImpl _nativeControlHost;
private readonly IStorageProvider _storageProvider;
public AvaloniaView View => _view; public AvaloniaView View => _view;
public TopLevelImpl(AvaloniaView view) public TopLevelImpl(AvaloniaView view)
{ {
_view = view; _view = view;
NativeControlHost = new NativeControlHostImpl(_view); _nativeControlHost = new NativeControlHostImpl(_view);
StorageProvider = new IOSStorageProvider(view); _storageProvider = new IOSStorageProvider(view);
} }
public void Dispose() public void Dispose()
@ -157,9 +158,25 @@ namespace Avalonia.iOS
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } =
new AcrylicPlatformCompensationLevels(); new AcrylicPlatformCompensationLevels();
public ITextInputMethodImpl? TextInputMethod => _view; public object? TryGetFeature(Type featureType)
public INativeControlHostImpl NativeControlHost { get; } {
public IStorageProvider StorageProvider { get; } if (featureType == typeof(IStorageProvider))
{
return _storageProvider;
}
if (featureType == typeof(ITextInputMethodImpl))
{
return _view;
}
if (featureType == typeof(INativeControlHostImpl))
{
return _nativeControlHost;
}
return null;
}
} }
[Export("layerClass")] [Export("layerClass")]

1
tests/Avalonia.Base.UnitTests/Input/PointerTestsBase.cs

@ -35,6 +35,7 @@ public abstract class PointerTestsBase
impl.DefaultValue = DefaultValue.Mock; impl.DefaultValue = DefaultValue.Mock;
impl.SetupAllProperties(); impl.SetupAllProperties();
impl.SetupGet(r => r.RenderScaling).Returns(1); impl.SetupGet(r => r.RenderScaling).Returns(1);
impl.Setup(r => r.TryGetFeature(It.IsAny<Type>())).Returns(null);
impl.Setup(r => r.CreateRenderer(It.IsAny<IRenderRoot>())).Returns(renderer); impl.Setup(r => r.CreateRenderer(It.IsAny<IRenderRoot>())).Returns(renderer);
impl.Setup(r => r.PointToScreen(It.IsAny<Point>())).Returns<Point>(p => new PixelPoint((int)p.X, (int)p.Y)); impl.Setup(r => r.PointToScreen(It.IsAny<Point>())).Returns<Point>(p => new PixelPoint((int)p.X, (int)p.Y));
impl.Setup(r => r.PointToClient(It.IsAny<PixelPoint>())).Returns<PixelPoint>(p => new Point(p.X, p.Y)); impl.Setup(r => r.PointToClient(It.IsAny<PixelPoint>())).Returns<PixelPoint>(p => new Point(p.X, p.Y));

1
tests/Avalonia.LeakTests/ControlTests.cs

@ -465,6 +465,7 @@ namespace Avalonia.LeakTests
var renderer = new Mock<IRenderer>(); var renderer = new Mock<IRenderer>();
renderer.Setup(x => x.Dispose()); renderer.Setup(x => x.Dispose());
var impl = new Mock<IWindowImpl>(); var impl = new Mock<IWindowImpl>();
impl.Setup(r => r.TryGetFeature(It.IsAny<Type>())).Returns(null);
impl.SetupGet(x => x.RenderScaling).Returns(1); impl.SetupGet(x => x.RenderScaling).Returns(1);
impl.SetupProperty(x => x.Closed); impl.SetupProperty(x => x.Closed);
impl.Setup(x => x.CreateRenderer(It.IsAny<IRenderRoot>())).Returns(renderer.Object); impl.Setup(x => x.CreateRenderer(It.IsAny<IRenderRoot>())).Returns(renderer.Object);

4
tests/Avalonia.UnitTests/CompositorTestServices.cs

@ -203,5 +203,7 @@ public class CompositorTestServices : IDisposable
} }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; }
public object TryGetFeature(Type featureType) => null;
} }
} }

3
tests/Avalonia.UnitTests/MockWindowingPlatform.cs

@ -35,6 +35,8 @@ namespace Avalonia.UnitTests
windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object); windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object);
windowImpl.Setup(x => x.Position).Returns(() => position); windowImpl.Setup(x => x.Position).Returns(() => position);
windowImpl.Setup(r => r.TryGetFeature(It.IsAny<Type>())).Returns(null);
windowImpl.Setup(x => x.CreatePopup()).Returns(() => windowImpl.Setup(x => x.CreatePopup()).Returns(() =>
{ {
return CreatePopupMock(windowImpl.Object).Object; return CreatePopupMock(windowImpl.Object).Object;
@ -95,6 +97,7 @@ namespace Avalonia.UnitTests
popupImpl.Setup(x => x.RenderScaling).Returns(1); popupImpl.Setup(x => x.RenderScaling).Returns(1);
popupImpl.Setup(x => x.PopupPositioner).Returns(positioner); popupImpl.Setup(x => x.PopupPositioner).Returns(positioner);
popupImpl.Setup(r => r.TryGetFeature(It.IsAny<Type>())).Returns(null);
popupImpl.Setup(x => x.Dispose()).Callback(() => popupImpl.Setup(x => x.Dispose()).Callback(() =>
{ {
popupImpl.Object.Closed?.Invoke(); popupImpl.Object.Closed?.Invoke();

Loading…
Cancel
Save