Browse Source

[AVN] Introduced ComObjectWeakPtr (#17041)

pull/17115/head
Nikita Tsukanov 1 year ago
committed by GitHub
parent
commit
e2a07cc04d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 63
      native/Avalonia.Native/inc/comimpl.h
  2. 81
      native/Avalonia.Native/src/OSX/AvnView.mm
  3. 99
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  4. 2
      native/Avalonia.Native/src/OSX/IWindowStateChanged.h

63
native/Avalonia.Native/inc/comimpl.h

@ -7,6 +7,7 @@
#define COMIMPL_H_INCLUDED
#include <cstring>
#include <memory>
/**
START_COM_CALL causes AddRef to be called at the beginning of a function.
@ -100,6 +101,13 @@ public:
return _obj;
}
template<class TCast> ComPtr<TCast> dynamicCast()
{
if(_obj == nullptr)
return nullptr;
return dynamic_cast<TCast*>(_obj);
}
TInterface** getPPV()
{
return &_obj;
@ -130,10 +138,18 @@ public:
}
};
class ComObjectWeakRefToken
{
public:
bool Alive = true;
};
class ComObject : public virtual IUnknown
{
private:
unsigned int _refCount;
std::shared_ptr<ComObjectWeakRefToken> _weakRefs;
public:
virtual ULONG AddRef()
@ -157,10 +173,22 @@ public:
_refCount = 1;
}
virtual ~ComObject()
{
if(_weakRefs)
_weakRefs->Alive = false;
}
std::shared_ptr<ComObjectWeakRefToken> __GetWeakRefToken()
{
if(_weakRefs == nullptr)
{
_weakRefs = std::make_shared<ComObjectWeakRefToken>();
}
return _weakRefs;
}
virtual ::HRESULT STDMETHODCALLTYPE QueryInterfaceImpl(REFIID riid, void **ppvObject) = 0;
@ -188,6 +216,41 @@ protected:
};
template<class TClass>
class ComObjectWeakPtr
{
private:
std::shared_ptr<ComObjectWeakRefToken> _token;
TClass* _rawPtr;
public:
ComPtr<TClass> tryGet()
{
if(_rawPtr == nullptr)
return nullptr;
if(_token->Alive)
return _rawPtr;
return nullptr;
}
template<class TCast> ComPtr<TCast> tryGetWithCast()
{
return tryGet().template dynamicCast<TCast>();
}
ComObjectWeakPtr(TClass* obj)
{
_rawPtr = obj;
if(obj)
_token = obj->__GetWeakRefToken();
}
ComObjectWeakPtr()
{
_rawPtr = nullptr;
_token = nullptr;
}
};
#define FORWARD_IUNKNOWN() \
virtual ULONG Release() override \
{ \

81
native/Avalonia.Native/src/OSX/AvnView.mm

@ -11,7 +11,7 @@
@implementation AvnView
{
ComPtr<TopLevelImpl> _parent;
ComObjectWeakPtr<TopLevelImpl> _parent;
NSTrackingArea* _area;
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed;
AvnInputModifiers _modifierState;
@ -132,7 +132,8 @@
_area = nullptr;
}
if (_parent == nullptr)
auto parent = _parent.tryGet();
if (parent == nullptr)
{
return;
}
@ -144,7 +145,7 @@
_area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr];
[self addTrackingArea:_area];
_parent->UpdateCursor();
parent->UpdateCursor();
auto fsize = [self convertSizeToBacking: [self frame].size];
@ -156,26 +157,28 @@
auto reason = [self inLiveResize] ? ResizeUser : _resizeReason;
_parent->TopLevelEvents->Resized(FromNSSize(newSize), reason);
parent->TopLevelEvents->Resized(FromNSSize(newSize), reason);
}
}
- (void)updateLayer
{
AvnInsidePotentialDeadlock deadlock;
if (_parent == nullptr)
auto parent = _parent.tryGet();
if (parent == nullptr)
{
return;
}
_parent->TopLevelEvents->RunRenderPriorityJobs();
parent->TopLevelEvents->RunRenderPriorityJobs();
if (_parent == nullptr)
parent = _parent.tryGet();
if (parent == nullptr)
{
return;
}
_parent->TopLevelEvents->Paint();
parent->TopLevelEvents->Paint();
}
- (void)drawRect:(NSRect)dirtyRect
@ -196,9 +199,10 @@
_lastPixelSize.Height = (int)fsize.height;
[self updateRenderTarget];
if(_parent != nullptr)
auto parent = _parent.tryGet();
if(parent != nullptr)
{
_parent->TopLevelEvents->ScalingChanged([[self window] backingScaleFactor]);
parent->TopLevelEvents->ScalingChanged([[self window] backingScaleFactor]);
}
[super viewDidChangeBackingProperties];
@ -206,7 +210,8 @@
- (bool) ignoreUserInput:(bool)trigerInputWhenDisabled
{
if(_parent == nullptr)
auto parent = _parent.tryGet();
if(parent == nullptr)
{
return TRUE;
}
@ -221,7 +226,7 @@
{
if(trigerInputWhenDisabled)
{
WindowImpl* windowImpl = dynamic_cast<WindowImpl*>(_parent.getRaw());
auto windowImpl = _parent.tryGetWithCast<WindowImpl>();
if(windowImpl == nullptr){
return FALSE;
@ -298,10 +303,10 @@
)
)
{
WindowBaseImpl* windowBase = dynamic_cast<WindowBaseImpl*>(_parent.getRaw());
auto windowBase = _parent.tryGetWithCast<WindowBaseImpl>();
if(windowBase != nullptr){
WindowBaseImpl* parent = windowBase->Parent;
auto parent = windowBase->Parent;
if(parent != nullptr){
auto parentWindow = parent->Window;
@ -313,10 +318,10 @@
}
}
if(_parent != nullptr)
auto parent = _parent.tryGet();
if(parent != nullptr)
{
_parent->TopLevelEvents->RawMouseEvent(type, timestamp, modifiers, point, delta);
parent->TopLevelEvents->RawMouseEvent(type, timestamp, modifiers, point, delta);
}
[super mouseMoved:event];
@ -324,7 +329,9 @@
- (BOOL) resignFirstResponder
{
_parent->TopLevelEvents->LostFocus();
auto parent = _parent.tryGet();
if(parent)
parent->TopLevelEvents->LostFocus();
return YES;
}
@ -463,7 +470,8 @@
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
{
if([self ignoreUserInput: false] || _parent == nullptr)
auto parent = _parent.tryGet();
if([self ignoreUserInput: false] || parent == nullptr)
{
return;
}
@ -477,7 +485,7 @@
auto timestamp = static_cast<uint64_t>([event timestamp] * 1000);
auto modifiers = [self getModifiers:[event modifierFlags]];
_parent->TopLevelEvents->RawKeyEvent(type, timestamp, modifiers, key, physicalKey, keySymbolUtf8);
parent->TopLevelEvents->RawKeyEvent(type, timestamp, modifiers, key, physicalKey, keySymbolUtf8);
}
- (void)setModifiers:(NSEventModifierFlags)modifierFlags
@ -551,12 +559,14 @@
}
- (bool) handleKeyDown: (NSTimeInterval) timestamp withKey:(AvnKey)key withPhysicalKey:(AvnPhysicalKey)physicalKey withModifiers:(AvnInputModifiers)modifiers withKeySymbol:(NSString*)keySymbol {
return _parent->TopLevelEvents->RawKeyEvent(KeyDown, timestamp, modifiers, key, physicalKey, [keySymbol UTF8String]);
auto parent = _parent.tryGet();
return parent->TopLevelEvents->RawKeyEvent(KeyDown, timestamp, modifiers, key, physicalKey, [keySymbol UTF8String]);
}
- (void)keyDown:(NSEvent *)event
{
if([self ignoreUserInput: false] || _parent == nullptr)
auto parent = _parent.tryGet();
if([self ignoreUserInput: false] || parent == nullptr)
{
return;
}
@ -573,7 +583,7 @@
auto modifiers = [self getModifiers:[event modifierFlags]];
//InputMethod is active
if(_parent->InputMethod->IsActive()){
if(parent->InputMethod->IsActive()){
auto hasInputModifier = modifiers != AvnInputModifiersNone;
//Handle keyDown first if an input modifier is present
@ -605,7 +615,7 @@
if(keySymbol != nullptr && key != AvnKeyEnter){
auto timestamp = static_cast<uint64_t>([event timestamp] * 1000);
_parent->TopLevelEvents->RawTextInputEvent(timestamp, [keySymbol UTF8String]);
parent->TopLevelEvents->RawTextInputEvent(timestamp, [keySymbol UTF8String]);
}
}
}
@ -681,16 +691,18 @@
}
_markedRange = NSMakeRange(_selectedRange.location, [markedText length]);
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]);
auto parent = _parent.tryGet();
if(parent->InputMethod->IsActive()){
parent->InputMethod->Client->SetPreeditText((char*)[markedText UTF8String]);
}
}
- (void)unmarkText
{
if(_parent->InputMethod->IsActive()){
_parent->InputMethod->Client->SetPreeditText(nullptr);
auto parent = _parent.tryGet();
if(parent->InputMethod->IsActive()){
parent->InputMethod->Client->SetPreeditText(nullptr);
}
_markedRange = NSMakeRange(_selectedRange.location, 0);
@ -718,7 +730,8 @@
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{
if(_parent == nullptr){
auto parent = _parent.tryGet();
if(parent == nullptr){
return;
}
@ -737,7 +750,7 @@
uint64_t timestamp = static_cast<uint64_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
_parent->TopLevelEvents->RawTextInputEvent(timestamp, [text UTF8String]);
parent->TopLevelEvents->RawTextInputEvent(timestamp, [text UTF8String]);
}
- (NSUInteger)characterIndexForPoint:(NSPoint)point
@ -747,7 +760,8 @@
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{
if(!_parent->InputMethod->IsActive()){
auto parent = _parent.tryGet();
if(!parent->InputMethod->IsActive()){
return NSZeroRect;
}
@ -763,7 +777,8 @@
NSDragOperation nsop = [info draggingSourceOperationMask];
auto effects = ConvertDragDropEffects(nsop);
int reffects = (int)_parent->TopLevelEvents
auto parent = _parent.tryGet();
int reffects = (int)parent->TopLevelEvents
->DragEvent(type, point, modifiers, effects,
CreateClipboard([info draggingPasteboard], nil),
GetAvnDataObjectHandleFromDraggingInfo(info));

99
native/Avalonia.Native/src/OSX/AvnWindow.mm

@ -29,7 +29,7 @@
@implementation CLASS_NAME
{
ComPtr<WindowBaseImpl> _parent;
ComObjectWeakPtr<WindowBaseImpl> _parent;
bool _closed;
bool _isEnabled;
bool _canBecomeKeyWindow;
@ -42,7 +42,8 @@
-(AvnView* _Nullable) view
{
return _parent->View;
auto parent = _parent.tryGet();
return parent ? parent->View : nullptr;
}
-(void) setIsExtended:(bool)value;
@ -52,7 +53,8 @@
-(bool) isDialog
{
return _parent->IsModal();
auto parent = _parent.tryGet();
return parent ? parent->IsModal() : false;
}
-(double) getExtendedTitleBarHeight
@ -194,7 +196,7 @@
- (BOOL)windowShouldClose:(NSWindow *_Nonnull)sender
{
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
auto window = _parent.tryGet().dynamicCast<WindowImpl>();
if(window != nullptr)
{
@ -212,20 +214,17 @@
- (void)windowWillClose:(NSNotification *_Nonnull)notification
{
_closed = true;
if(_parent)
auto window = _parent.tryGetWithCast<WindowImpl>();
if(window)
{
ComPtr<WindowBaseImpl> parent = _parent;
_parent = NULL;
auto window = dynamic_cast<WindowImpl*>(parent.getRaw());
if(window != nullptr)
{
window->SetParent(nullptr);
}
parent->BaseEvents->Closed();
[parent->View onClosed];
window->BaseEvents->Closed();
[window->View onClosed];
}
}
@ -247,7 +246,7 @@
if(_canBecomeKeyWindow && !_closed)
{
// If the window has a child window being shown as a dialog then don't allow it to become the key window.
auto parent = dynamic_cast<WindowImpl*>(_parent.getRaw());
auto parent = _parent.tryGet().dynamicCast<WindowImpl>();
if(parent != nullptr)
{
@ -286,9 +285,10 @@
{
[self showWindowMenuWithAppMenu];
if(_parent != nullptr)
auto parent = _parent.tryGet();
if(parent != nullptr)
{
_parent->BaseEvents->Activated();
parent->BaseEvents->Activated();
}
[super becomeKeyWindow];
@ -296,19 +296,21 @@
- (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification
{
if (_parent == nullptr)
auto parent = _parent.tryGet();
if (parent == nullptr)
return;
if (_parent->View != nullptr)
[_parent->View setModifiers:NSEvent.modifierFlags];
if (parent->View != nullptr)
[parent->View setModifiers:NSEvent.modifierFlags];
_parent->BringToFront();
parent->BringToFront();
dispatch_async(dispatch_get_main_queue(), ^{
@try {
[self invalidateShadow];
if (self->_parent != nullptr)
self->_parent->BringToFront();
auto parent = self->_parent.tryGet();
if (parent != nullptr)
parent->BringToFront();
}
@finally{
}
@ -317,7 +319,7 @@
- (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -327,7 +329,7 @@
- (void)windowDidDeminiaturize:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -337,7 +339,7 @@
- (void)windowDidResize:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -347,7 +349,7 @@
- (void)windowWillExitFullScreen:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -357,7 +359,7 @@
- (void)windowDidExitFullScreen:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -381,7 +383,7 @@
- (void)windowWillEnterFullScreen:(NSNotification *_Nonnull)notification
{
_isTransitioningToFullScreen = true;
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -392,7 +394,7 @@
- (void)windowDidEnterFullScreen:(NSNotification *_Nonnull)notification
{
_isTransitioningToFullScreen = false;
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
auto parent = _parent.tryGetWithCast<IWindowStateChanged>();
if(parent != nullptr)
{
@ -403,13 +405,15 @@
- (BOOL)windowShouldZoom:(NSWindow *_Nonnull)window toFrame:(NSRect)newFrame
{
return _parent->CanZoom();
auto parent = _parent.tryGet();
return parent ? parent->CanZoom() : false;
}
-(void)windowDidResignKey:(NSNotification* _Nonnull)notification
{
if(_parent)
_parent->BaseEvents->Deactivated();
auto parent = _parent.tryGet();
if(parent)
parent->BaseEvents->Deactivated();
[self showAppMenuOnly];
@ -420,25 +424,25 @@
{
AvnPoint position;
if(_parent != nullptr)
auto parent = _parent.tryGet();
if(parent != nullptr)
{
auto cparent = dynamic_cast<WindowImpl*>(_parent.getRaw());
if(cparent != nullptr)
auto window = parent.dynamicCast<WindowImpl>();
if(window != nullptr)
{
if(!cparent->IsShown())
if(!window->IsShown())
{
return;
}
if(cparent->WindowState() == Maximized)
if(window->WindowState() == Maximized)
{
cparent->SetWindowState(Normal);
window->SetWindowState(Normal);
}
}
_parent->GetPosition(&position);
_parent->BaseEvents->PositionChanged(position);
parent->GetPosition(&position);
parent->BaseEvents->PositionChanged(position);
}
}
@ -452,14 +456,15 @@
{
[super sendEvent:event];
auto parent = _parent.tryGetWithCast<WindowImpl>();
/// This is to detect non-client clicks. This can only be done on Windows... not popups, hence the dynamic_cast.
if(_parent != nullptr && dynamic_cast<WindowImpl*>(_parent.getRaw()) != nullptr)
if(parent)
{
switch(event.type)
{
case NSEventTypeLeftMouseDown:
{
AvnView* view = _parent->View;
AvnView* view = parent->View;
NSPoint windowPoint = [event locationInWindow];
NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil];
@ -469,19 +474,19 @@
auto point = [self translateLocalPoint:avnPoint];
AvnVector delta = { 0, 0 };
_parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint64>([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint64>([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
}
if(!_isTransitioningToFullScreen)
{
_parent->BringToFront();
parent->BringToFront();
}
}
break;
case NSEventTypeMouseEntered:
{
_parent->UpdateCursor();
parent->UpdateCursor();
}
break;
@ -516,9 +521,10 @@
- (IAvnAutomationPeer* _Nonnull) automationPeer
{
auto parent = _parent.tryGet();
if (_automationPeer == nullptr)
{
_automationPeer = _parent->BaseEvents->GetAutomationPeer();
_automationPeer = parent->BaseEvents->GetAutomationPeer();
_automationNode = new AvnAutomationNode(self);
_automationPeer->SetNode(_automationNode);
}
@ -528,7 +534,8 @@
- (void)raiseChildrenChanged
{
[_parent->View raiseAccessibilityChildrenChanged];
auto parent = _parent.tryGet();
[parent->View raiseAccessibilityChildrenChanged];
}
- (void)raiseFocusChanged

2
native/Avalonia.Native/src/OSX/IWindowStateChanged.h

@ -6,7 +6,7 @@
#ifndef AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H
#define AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H
struct IWindowStateChanged
struct IWindowStateChanged: public IUnknown
{
virtual void WindowStateChanged () = 0;
virtual void StartStateTransition () = 0;

Loading…
Cancel
Save