Browse Source
* Introduce Avalonia.Native TopLevelImpl * Update Avalonia.Native.csproj Revert changepull/16061/head
committed by
GitHub
60 changed files with 1378 additions and 995 deletions
@ -1,9 +0,0 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 06/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_POPUPIMPL_H |
|||
#define AVALONIA_NATIVE_OSX_POPUPIMPL_H |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_POPUPIMPL_H
|
|||
@ -0,0 +1,76 @@ |
|||
//
|
|||
// TopLevelImpl.h
|
|||
// Avalonia.Native.OSX
|
|||
//
|
|||
// Created by Benedikt Stebner on 16.05.24.
|
|||
// Copyright © 2024 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef TopLevelImpl_h |
|||
#define TopLevelImpl_h |
|||
|
|||
#include "rendertarget.h" |
|||
#include "INSWindowHolder.h" |
|||
#include "AvnTextInputMethod.h" |
|||
#include "AutoFitContentView.h" |
|||
#include <list> |
|||
|
|||
class TopLevelImpl : public virtual ComObject, |
|||
public virtual IAvnTopLevel, |
|||
public INSViewHolder{ |
|||
|
|||
public: |
|||
FORWARD_IUNKNOWN() |
|||
BEGIN_INTERFACE_MAP() |
|||
INTERFACE_MAP_ENTRY(IAvnTopLevel, IID_IAvnTopLevel) |
|||
END_INTERFACE_MAP() |
|||
|
|||
virtual ~TopLevelImpl(); |
|||
|
|||
TopLevelImpl(IAvnTopLevelEvents* events); |
|||
|
|||
virtual AvnView *GetNSView() override; |
|||
|
|||
virtual HRESULT SetCursor(IAvnCursor* cursor) override; |
|||
|
|||
virtual HRESULT GetScaling(double*ret) override; |
|||
|
|||
virtual HRESULT GetClientSize(AvnSize *ret) override; |
|||
|
|||
virtual HRESULT GetInputMethod(IAvnTextInputMethod **ppv) override; |
|||
|
|||
virtual HRESULT ObtainNSViewHandle(void** retOut) override; |
|||
|
|||
virtual HRESULT ObtainNSViewHandleRetained(void** retOut) override; |
|||
|
|||
virtual HRESULT CreateSoftwareRenderTarget(IAvnSoftwareRenderTarget** ret) override; |
|||
|
|||
virtual HRESULT CreateMetalRenderTarget(IAvnMetalDevice* device, IAvnMetalRenderTarget** ret) override; |
|||
|
|||
virtual HRESULT CreateGlRenderTarget(IAvnGlContext* context, IAvnGlSurfaceRenderTarget** ret) override; |
|||
|
|||
virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost **retOut) override; |
|||
|
|||
virtual HRESULT Invalidate() override; |
|||
|
|||
virtual HRESULT PointToClient(AvnPoint point, AvnPoint *ret) override; |
|||
|
|||
virtual HRESULT PointToScreen(AvnPoint point, AvnPoint *ret) override; |
|||
|
|||
virtual HRESULT SetTransparencyMode(AvnWindowTransparencyMode mode) override; |
|||
|
|||
protected: |
|||
NSCursor *cursor; |
|||
virtual void UpdateAppearance(); |
|||
|
|||
public: |
|||
NSObject<IRenderTarget> *currentRenderTarget; |
|||
ComPtr<AvnTextInputMethod> InputMethod; |
|||
ComPtr<IAvnTopLevelEvents> TopLevelEvents; |
|||
AvnView *View; |
|||
|
|||
void UpdateCursor(); |
|||
virtual void SetClientSize(NSSize size); |
|||
}; |
|||
|
|||
#endif /* TopLevelImpl_h */ |
|||
@ -0,0 +1,251 @@ |
|||
#import <AppKit/AppKit.h> |
|||
#import <Cocoa/Cocoa.h> |
|||
#include "automation.h" |
|||
#include "cursor.h" |
|||
#include "AutoFitContentView.h" |
|||
#include "TopLevelImpl.h" |
|||
#include "AvnTextInputMethod.h" |
|||
#include "AvnView.h" |
|||
|
|||
TopLevelImpl::~TopLevelImpl() { |
|||
View = nullptr; |
|||
} |
|||
|
|||
TopLevelImpl::TopLevelImpl(IAvnTopLevelEvents *events) { |
|||
TopLevelEvents = events; |
|||
|
|||
View = [[AvnView alloc] initWithParent:this]; |
|||
InputMethod = new AvnTextInputMethod(View); |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::GetScaling(double *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) |
|||
return E_POINTER; |
|||
|
|||
if ([View window] == nullptr) { |
|||
*ret = 1; |
|||
return S_OK; |
|||
} |
|||
|
|||
*ret = [[View window] backingScaleFactor]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::GetClientSize(AvnSize *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) |
|||
return E_POINTER; |
|||
|
|||
NSRect frame = [View frame]; |
|||
|
|||
ret->Width = frame.size.width; |
|||
ret->Height = frame.size.height; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::GetInputMethod(IAvnTextInputMethod **retOut) { |
|||
START_COM_CALL; |
|||
|
|||
*retOut = InputMethod; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::ObtainNSViewHandle(void **ret) { |
|||
START_COM_CALL; |
|||
|
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = (__bridge void *) View; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::ObtainNSViewHandleRetained(void **ret) { |
|||
START_COM_CALL; |
|||
|
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = (__bridge_retained void *) View; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::SetCursor(IAvnCursor *cursor) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
Cursor *avnCursor = dynamic_cast<Cursor *>(cursor); |
|||
this->cursor = avnCursor->GetNative(); |
|||
UpdateCursor(); |
|||
|
|||
if (avnCursor->IsHidden()) { |
|||
[NSCursor hide]; |
|||
} else { |
|||
[NSCursor unhide]; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
void TopLevelImpl::UpdateCursor() { |
|||
if (cursor != nil) { |
|||
[cursor set]; |
|||
} |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::CreateSoftwareRenderTarget(IAvnSoftwareRenderTarget **ppv) { |
|||
START_COM_CALL; |
|||
|
|||
if(![NSThread isMainThread]) |
|||
return COR_E_INVALIDOPERATION; |
|||
|
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
|
|||
auto target = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext: nil]; |
|||
*ppv = [target createSoftwareRenderTarget]; |
|||
[View setRenderTarget: target]; |
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::CreateGlRenderTarget(IAvnGlContext* glContext, IAvnGlSurfaceRenderTarget **ppv) { |
|||
START_COM_CALL; |
|||
|
|||
if(![NSThread isMainThread]) |
|||
return COR_E_INVALIDOPERATION; |
|||
|
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
|
|||
auto target = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext: glContext]; |
|||
*ppv = [target createSurfaceRenderTarget]; |
|||
[View setRenderTarget: target]; |
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::CreateMetalRenderTarget(IAvnMetalDevice* device, IAvnMetalRenderTarget **ppv) { |
|||
START_COM_CALL; |
|||
|
|||
if(![NSThread isMainThread]) |
|||
return COR_E_INVALIDOPERATION; |
|||
|
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
|
|||
auto target = [[MetalRenderTarget alloc] initWithDevice: device]; |
|||
[View setRenderTarget: target]; |
|||
[target getRenderTarget: ppv]; |
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::CreateNativeControlHost(IAvnNativeControlHost **retOut) { |
|||
START_COM_CALL; |
|||
|
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
*retOut = ::CreateNativeControlHost(View); |
|||
return S_OK; |
|||
} |
|||
|
|||
AvnView *TopLevelImpl::GetNSView() { |
|||
return View; |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::Invalidate() { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
[View setNeedsDisplayInRect:[View frame]]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::PointToClient(AvnPoint point, AvnPoint *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
auto window = [View window]; |
|||
|
|||
if(window == nullptr){ |
|||
ret = &point; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
point = ConvertPointY(point); |
|||
NSRect convertRect = [window convertRectFromScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)]; |
|||
auto viewPoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y); |
|||
|
|||
*ret = [View translateLocalPoint:ToAvnPoint(viewPoint)]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::PointToScreen(AvnPoint point, AvnPoint *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
auto window = [View window]; |
|||
|
|||
if(window == nullptr){ |
|||
ret = &point; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
auto cocoaViewPoint = ToNSPoint([View translateLocalPoint:point]); |
|||
NSRect convertRect = [window convertRectToScreen:NSMakeRect(cocoaViewPoint.x, cocoaViewPoint.y, 0.0, 0.0)]; |
|||
auto cocoaScreenPoint = NSPointFromCGPoint(NSMakePoint(convertRect.origin.x, convertRect.origin.y)); |
|||
*ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint)); |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT TopLevelImpl::SetTransparencyMode(AvnWindowTransparencyMode mode) { |
|||
START_COM_CALL; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
void TopLevelImpl::UpdateAppearance() { |
|||
|
|||
} |
|||
|
|||
void TopLevelImpl::SetClientSize(NSSize size){ |
|||
[View setFrameSize:size]; |
|||
} |
|||
|
|||
extern IAvnTopLevel* CreateAvnTopLevel(IAvnTopLevelEvents* events) |
|||
{ |
|||
@autoreleasepool |
|||
{ |
|||
IAvnTopLevel* ptr = (IAvnTopLevel*)new TopLevelImpl(events); |
|||
return ptr; |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Avalonia.Native.Interop; |
|||
|
|||
namespace Avalonia.Native |
|||
{ |
|||
internal class EmbeddableTopLevelImpl : TopLevelImpl |
|||
{ |
|||
public EmbeddableTopLevelImpl(IAvaloniaNativeFactory factory) : base(factory) |
|||
{ |
|||
using (var e = new TopLevelEvents(this)) |
|||
{ |
|||
Init(new MacOSTopLevelHandle(factory.CreateTopLevel(e)), factory.CreateScreens()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,557 @@ |
|||
#nullable enable |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.Automation.Peers; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Platform; |
|||
using Avalonia.Controls.Platform.Surfaces; |
|||
using Avalonia.Input; |
|||
using Avalonia.Input.Platform; |
|||
using Avalonia.Input.Raw; |
|||
using Avalonia.Input.TextInput; |
|||
using Avalonia.Native.Interop; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Platform.Storage; |
|||
using Avalonia.Platform.Storage.FileIO; |
|||
using Avalonia.Rendering.Composition; |
|||
using Avalonia.Threading; |
|||
|
|||
namespace Avalonia.Native; |
|||
|
|||
internal class MacOSTopLevelHandle : IPlatformHandle, IMacOSTopLevelPlatformHandle |
|||
{ |
|||
internal MacOSTopLevelHandle(IAvnTopLevel native) |
|||
{ |
|||
Native = native; |
|||
|
|||
HandleDescriptor = "NSView"; |
|||
|
|||
Handle = NSView; |
|||
} |
|||
|
|||
internal MacOSTopLevelHandle(IAvnWindowBase native) |
|||
{ |
|||
Native = native; |
|||
|
|||
HandleDescriptor = "NSWindow"; |
|||
|
|||
Handle = NSWindow; |
|||
} |
|||
|
|||
internal IAvnTopLevel Native { get; } |
|||
|
|||
public IntPtr Handle { get; } |
|||
|
|||
public string HandleDescriptor { get; } |
|||
|
|||
public IntPtr NSView => Native.ObtainNSViewHandle(); |
|||
|
|||
public IntPtr GetNSViewRetained() |
|||
{ |
|||
return Native.ObtainNSViewHandleRetained(); |
|||
} |
|||
|
|||
public IntPtr NSWindow => (Native as IAvnWindowBase)?.ObtainNSWindowHandle() ?? IntPtr.Zero; |
|||
|
|||
public IntPtr GetNSWindowRetained() |
|||
{ |
|||
return (Native as IAvnWindowBase)?.ObtainNSWindowHandleRetained() ?? IntPtr.Zero; |
|||
} |
|||
} |
|||
|
|||
internal class TopLevelImpl : ITopLevelImpl, IFramebufferPlatformSurface |
|||
{ |
|||
protected IInputRoot? _inputRoot; |
|||
private NativeControlHostImpl? _nativeControlHost; |
|||
private IStorageProvider? _storageProvider; |
|||
private PlatformBehaviorInhibition? _platformBehaviorInhibition; |
|||
|
|||
private readonly MouseDevice? _mouse; |
|||
private readonly IKeyboardDevice? _keyboard; |
|||
private readonly ICursorFactory? _cursorFactory; |
|||
|
|||
protected readonly IAvaloniaNativeFactory Factory; |
|||
|
|||
private Size _savedLogicalSize; |
|||
private double _savedScaling; |
|||
private WindowTransparencyLevel _transparencyLevel = WindowTransparencyLevel.None; |
|||
|
|||
protected MacOSTopLevelHandle? _handle; |
|||
|
|||
private object _syncRoot = new object(); |
|||
private IEnumerable<object>? _surfaces; |
|||
|
|||
public TopLevelImpl(IAvaloniaNativeFactory factory) |
|||
{ |
|||
Factory = factory; |
|||
|
|||
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>(); |
|||
_mouse = new MouseDevice(); |
|||
_cursorFactory = AvaloniaLocator.Current.GetService<ICursorFactory>(); |
|||
} |
|||
|
|||
internal virtual void Init(MacOSTopLevelHandle handle, IAvnScreens screens) |
|||
{ |
|||
_handle = handle; |
|||
_savedLogicalSize = ClientSize; |
|||
_savedScaling = RenderScaling; |
|||
_nativeControlHost = new NativeControlHostImpl(Native!.CreateNativeControlHost()); |
|||
_storageProvider = new SystemDialogs(this, Factory.CreateSystemDialogs()); |
|||
_platformBehaviorInhibition = new PlatformBehaviorInhibition(Factory.CreatePlatformBehaviorInhibition()); |
|||
_surfaces = new object[] { new GlPlatformSurface(Native), new MetalPlatformSurface(Native), this }; |
|||
|
|||
Screen = new ScreenImpl(screens); |
|||
InputMethod = new AvaloniaNativeTextInputMethod(Native); |
|||
} |
|||
|
|||
public double DesktopScaling => 1; |
|||
|
|||
public IAvnTopLevel? Native => _handle?.Native; |
|||
public IPlatformHandle? Handle => _handle; |
|||
public AvaloniaNativeTextInputMethod? InputMethod { get; private set; } |
|||
public Size ClientSize |
|||
{ |
|||
get |
|||
{ |
|||
if (Native == null) |
|||
{ |
|||
return default; |
|||
} |
|||
|
|||
var s = Native.ClientSize; |
|||
return new Size(s.Width, s.Height); |
|||
|
|||
} |
|||
} |
|||
public double RenderScaling => Native?.Scaling ?? 1; |
|||
public IEnumerable<object> Surfaces => _surfaces ?? Array.Empty<object>(); |
|||
public Action<RawInputEventArgs>? Input { get; set; } |
|||
public Action<Rect>? Paint { get; set; } |
|||
public Action<Size, WindowResizeReason>? Resized { get; set; } |
|||
public Action<double>? ScalingChanged { get; set; } |
|||
public Action<WindowTransparencyLevel>? TransparencyLevelChanged { get; set; } |
|||
public Compositor Compositor => AvaloniaNativePlatform.Compositor; |
|||
public Action? Closed { get; set; } |
|||
public Action? LostFocus { get; set; } |
|||
|
|||
public WindowTransparencyLevel TransparencyLevel |
|||
{ |
|||
get => _transparencyLevel; |
|||
private set |
|||
{ |
|||
if (_transparencyLevel != value) |
|||
{ |
|||
_transparencyLevel = value; |
|||
TransparencyLevelChanged?.Invoke(value); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 0, 0); |
|||
public virtual void SetFrameThemeVariant(PlatformThemeVariant themeVariant) |
|||
{ |
|||
//noop
|
|||
} |
|||
|
|||
public IMouseDevice? MouseDevice => _mouse; |
|||
|
|||
public INativeControlHostImpl? NativeControlHost => _nativeControlHost; |
|||
|
|||
public IScreenImpl? Screen { get; private set; } |
|||
|
|||
public AutomationPeer? GetAutomationPeer() |
|||
{ |
|||
return _inputRoot is Control c ? ControlAutomationPeer.CreatePeerForElement(c) : null; |
|||
} |
|||
|
|||
public bool RawTextInputEvent(ulong timeStamp, string text) |
|||
{ |
|||
if (_inputRoot is null) |
|||
return false; |
|||
|
|||
if (_keyboard is null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); |
|||
|
|||
var args = new RawTextInputEventArgs(_keyboard, timeStamp, _inputRoot, text); |
|||
|
|||
Input?.Invoke(args); |
|||
|
|||
return args.Handled; |
|||
} |
|||
|
|||
public bool RawKeyEvent( |
|||
AvnRawKeyEventType type, |
|||
ulong timeStamp, |
|||
AvnInputModifiers modifiers, |
|||
AvnKey key, |
|||
AvnPhysicalKey physicalKey, |
|||
string keySymbol) |
|||
{ |
|||
if (_inputRoot is null) |
|||
return false; |
|||
|
|||
if (_keyboard is null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); |
|||
|
|||
var args = new RawKeyEventArgs( |
|||
_keyboard, |
|||
timeStamp, |
|||
_inputRoot, |
|||
(RawKeyEventType)type, |
|||
(Key)key, |
|||
(RawInputModifiers)modifiers, |
|||
(PhysicalKey)physicalKey, |
|||
keySymbol); |
|||
|
|||
Input?.Invoke(args); |
|||
|
|||
return args.Handled; |
|||
} |
|||
|
|||
public void RawMouseEvent(AvnRawMouseEventType type, ulong timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) |
|||
{ |
|||
if (_inputRoot is null) |
|||
return; |
|||
|
|||
if (_mouse is null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); |
|||
|
|||
switch (type) |
|||
{ |
|||
case AvnRawMouseEventType.Wheel: |
|||
Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, |
|||
point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (RawInputModifiers)modifiers)); |
|||
break; |
|||
|
|||
case AvnRawMouseEventType.Magnify: |
|||
Input?.Invoke(new RawPointerGestureEventArgs(_mouse, timeStamp, _inputRoot, RawPointerEventType.Magnify, |
|||
point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (RawInputModifiers)modifiers)); |
|||
break; |
|||
|
|||
case AvnRawMouseEventType.Rotate: |
|||
Input?.Invoke(new RawPointerGestureEventArgs(_mouse, timeStamp, _inputRoot, RawPointerEventType.Rotate, |
|||
point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (RawInputModifiers)modifiers)); |
|||
break; |
|||
|
|||
case AvnRawMouseEventType.Swipe: |
|||
Input?.Invoke(new RawPointerGestureEventArgs(_mouse, timeStamp, _inputRoot, RawPointerEventType.Swipe, |
|||
point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (RawInputModifiers)modifiers)); |
|||
break; |
|||
|
|||
default: |
|||
var e = new RawPointerEventArgs(_mouse, timeStamp, _inputRoot, (RawPointerEventType)type, |
|||
point.ToAvaloniaPoint(), (RawInputModifiers)modifiers); |
|||
|
|||
if (!ChromeHitTest(e)) |
|||
{ |
|||
Input?.Invoke(e); |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public void Invalidate() |
|||
{ |
|||
Native?.Invalidate(); |
|||
} |
|||
|
|||
public void SetInputRoot(IInputRoot inputRoot) |
|||
{ |
|||
_inputRoot = inputRoot; |
|||
} |
|||
|
|||
public Point PointToClient(PixelPoint point) |
|||
{ |
|||
return Native?.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint() ?? default; |
|||
} |
|||
|
|||
public PixelPoint PointToScreen(Point point) |
|||
{ |
|||
return Native?.PointToScreen(point.ToAvnPoint()).ToAvaloniaPixelPoint() ?? default; |
|||
} |
|||
|
|||
public void SetCursor(ICursorImpl? cursor) |
|||
{ |
|||
if (Native == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var newCursor = cursor as AvaloniaNativeCursor; |
|||
newCursor ??= (_cursorFactory?.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor); |
|||
Native.SetCursor(newCursor?.Cursor); |
|||
} |
|||
|
|||
public virtual IPopupImpl CreatePopup() |
|||
{ |
|||
return new PopupImpl(Factory, this); |
|||
} |
|||
|
|||
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels) |
|||
{ |
|||
foreach (var level in transparencyLevels) |
|||
{ |
|||
AvnWindowTransparencyMode? mode = null; |
|||
|
|||
if (level == WindowTransparencyLevel.None) |
|||
mode = AvnWindowTransparencyMode.Opaque; |
|||
if (level == WindowTransparencyLevel.Transparent) |
|||
mode = AvnWindowTransparencyMode.Transparent; |
|||
else if (level == WindowTransparencyLevel.AcrylicBlur) |
|||
mode = AvnWindowTransparencyMode.Blur; |
|||
|
|||
if (mode.HasValue && level != TransparencyLevel) |
|||
{ |
|||
Native?.SetTransparencyMode(mode.Value); |
|||
TransparencyLevel = level; |
|||
return; |
|||
} |
|||
} |
|||
|
|||
// If we get here, we didn't find a supported level. Use the default of None.
|
|||
if (TransparencyLevel != WindowTransparencyLevel.None) |
|||
{ |
|||
Native?.SetTransparencyMode(AvnWindowTransparencyMode.Opaque); |
|||
TransparencyLevel = WindowTransparencyLevel.None; |
|||
} |
|||
} |
|||
|
|||
public virtual object? TryGetFeature(Type featureType) |
|||
{ |
|||
if (featureType == typeof(ITextInputMethodImpl)) |
|||
{ |
|||
return InputMethod; |
|||
} |
|||
|
|||
if (featureType == typeof(INativeControlHostImpl)) |
|||
{ |
|||
return _nativeControlHost; |
|||
} |
|||
|
|||
if (featureType == typeof(IStorageProvider)) |
|||
{ |
|||
return _storageProvider; |
|||
} |
|||
|
|||
if (featureType == typeof(IPlatformBehaviorInhibition)) |
|||
{ |
|||
return _platformBehaviorInhibition; |
|||
} |
|||
|
|||
if (featureType == typeof(IClipboard)) |
|||
{ |
|||
return AvaloniaLocator.Current.GetRequiredService<IClipboard>(); |
|||
} |
|||
|
|||
if (featureType == typeof(ILauncher)) |
|||
{ |
|||
return new BclLauncher(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public virtual void Dispose() |
|||
{ |
|||
Native?.Dispose(); |
|||
_handle = null; |
|||
|
|||
_nativeControlHost?.Dispose(); |
|||
_nativeControlHost = null; |
|||
|
|||
(Screen as ScreenImpl)?.Dispose(); |
|||
_mouse?.Dispose(); |
|||
} |
|||
|
|||
protected virtual bool ChromeHitTest(RawPointerEventArgs e) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
IFramebufferRenderTarget IFramebufferPlatformSurface.CreateFramebufferRenderTarget() |
|||
{ |
|||
if (!Dispatcher.UIThread.CheckAccess()) |
|||
throw new RenderTargetNotReadyException(); |
|||
|
|||
var nativeRenderTarget = Native?.CreateSoftwareRenderTarget(); |
|||
|
|||
if (nativeRenderTarget is null) |
|||
{ |
|||
throw new RenderTargetNotReadyException(); |
|||
} |
|||
|
|||
return new FramebufferRenderTarget(this, nativeRenderTarget); |
|||
} |
|||
|
|||
protected internal unsafe class TopLevelEvents : NativeCallbackBase, IAvnTopLevelEvents |
|||
{ |
|||
private readonly TopLevelImpl _parent; |
|||
|
|||
public TopLevelEvents(TopLevelImpl parent) |
|||
{ |
|||
_parent = parent; |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.Closed() |
|||
{ |
|||
var n = _parent.Native; |
|||
|
|||
try |
|||
{ |
|||
_parent?.Closed?.Invoke(); |
|||
} |
|||
finally |
|||
{ |
|||
|
|||
_parent?.Dispose(); |
|||
n?.Dispose(); |
|||
} |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.Paint() |
|||
{ |
|||
Dispatcher.UIThread.RunJobs(DispatcherPriority.UiThreadRender); |
|||
var s = _parent.ClientSize; |
|||
_parent.Paint?.Invoke(new Rect(0, 0, s.Width, s.Height)); |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.Resized(AvnSize* size, AvnPlatformResizeReason reason) |
|||
{ |
|||
if (_parent?.Native == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var s = new Size(size->Width, size->Height); |
|||
_parent._savedLogicalSize = s; |
|||
_parent.Resized?.Invoke(s, (WindowResizeReason)reason); |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.RawMouseEvent(AvnRawMouseEventType type, ulong timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) |
|||
{ |
|||
_parent.RawMouseEvent(type, timeStamp, modifiers, point, delta); |
|||
} |
|||
|
|||
int IAvnTopLevelEvents.RawKeyEvent(AvnRawKeyEventType type, ulong timeStamp, AvnInputModifiers modifiers, AvnKey key, AvnPhysicalKey physicalKey, string keySymbol) |
|||
{ |
|||
return _parent.RawKeyEvent(type, timeStamp, modifiers, key, physicalKey, keySymbol).AsComBool(); |
|||
} |
|||
|
|||
int IAvnTopLevelEvents.RawTextInputEvent(ulong timeStamp, string text) |
|||
{ |
|||
return _parent.RawTextInputEvent(timeStamp, text).AsComBool(); |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.ScalingChanged(double scaling) |
|||
{ |
|||
_parent._savedScaling = scaling; |
|||
_parent.ScalingChanged?.Invoke(scaling); |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.RunRenderPriorityJobs() |
|||
{ |
|||
Dispatcher.UIThread.RunJobs(DispatcherPriority.UiThreadRender); |
|||
} |
|||
|
|||
void IAvnTopLevelEvents.LostFocus() |
|||
{ |
|||
_parent.LostFocus?.Invoke(); |
|||
} |
|||
|
|||
AvnDragDropEffects IAvnTopLevelEvents.DragEvent(AvnDragEventType type, AvnPoint position, |
|||
AvnInputModifiers modifiers, |
|||
AvnDragDropEffects effects, |
|||
IAvnClipboard clipboard, IntPtr dataObjectHandle) |
|||
{ |
|||
var device = AvaloniaLocator.Current.GetService<IDragDropDevice>(); |
|||
|
|||
if (device is null) |
|||
{ |
|||
return AvnDragDropEffects.None; |
|||
} |
|||
|
|||
if (_parent._inputRoot is null) |
|||
{ |
|||
return AvnDragDropEffects.None; |
|||
} |
|||
|
|||
IDataObject? dataObject = null; |
|||
if (dataObjectHandle != IntPtr.Zero) |
|||
dataObject = GCHandle.FromIntPtr(dataObjectHandle).Target as IDataObject; |
|||
|
|||
using (var clipboardDataObject = new ClipboardDataObject(clipboard)) |
|||
{ |
|||
if (dataObject == null) |
|||
dataObject = clipboardDataObject; |
|||
|
|||
var args = new RawDragEvent(device, (RawDragEventType)type, |
|||
_parent._inputRoot, position.ToAvaloniaPoint(), dataObject, (DragDropEffects)effects, |
|||
(RawInputModifiers)modifiers); |
|||
_parent.Input(args); |
|||
return (AvnDragDropEffects)args.Effects; |
|||
} |
|||
} |
|||
|
|||
IAvnAutomationPeer? IAvnTopLevelEvents.AutomationPeer |
|||
{ |
|||
get |
|||
{ |
|||
var native = _parent.GetAutomationPeer(); |
|||
|
|||
return native is null ? null : AvnAutomationPeer.Wrap(native); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private class FramebufferRenderTarget : IFramebufferRenderTarget |
|||
{ |
|||
private readonly TopLevelImpl _parent; |
|||
private IAvnSoftwareRenderTarget? _target; |
|||
|
|||
public FramebufferRenderTarget(TopLevelImpl parent, IAvnSoftwareRenderTarget target) |
|||
{ |
|||
_parent = parent; |
|||
_target = target; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
lock (_parent._syncRoot) |
|||
{ |
|||
_target?.Dispose(); |
|||
_target = null; |
|||
} |
|||
} |
|||
|
|||
public ILockedFramebuffer Lock() |
|||
{ |
|||
var w = _parent._savedLogicalSize.Width * _parent._savedScaling; |
|||
var h = _parent._savedLogicalSize.Height * _parent._savedScaling; |
|||
var dpi = _parent._savedScaling * 96; |
|||
return new DeferredFramebuffer(_target, cb => |
|||
{ |
|||
lock (_parent._syncRoot) |
|||
{ |
|||
if (_parent.Native != null && _target != null) |
|||
{ |
|||
cb(_parent.Native); |
|||
} |
|||
} |
|||
}, (int)w, (int)h, new Vector(dpi, dpi)); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue