Skip to content

Commit

Permalink
[AVN] Introduced ComObjectWeakPtr (#17041)
Browse files Browse the repository at this point in the history
  • Loading branch information
kekekeks authored Sep 24, 2024
1 parent 04e76a9 commit e2a07cc
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 80 deletions.
63 changes: 63 additions & 0 deletions native/Avalonia.Native/inc/comimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -100,6 +101,13 @@ class ComPtr
return _obj;
}

template<class TCast> ComPtr<TCast> dynamicCast()
{
if(_obj == nullptr)
return nullptr;
return dynamic_cast<TCast*>(_obj);
}

TInterface** getPPV()
{
return &_obj;
Expand Down Expand Up @@ -130,10 +138,18 @@ class ComPtr
}
};

class ComObjectWeakRefToken
{
public:
bool Alive = true;
};


class ComObject : public virtual IUnknown
{
private:
unsigned int _refCount;
std::shared_ptr<ComObjectWeakRefToken> _weakRefs;
public:

virtual ULONG AddRef()
Expand All @@ -157,10 +173,22 @@ class ComObject : public virtual IUnknown
_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;

Expand Down Expand Up @@ -188,6 +216,41 @@ class ComObject : public virtual IUnknown
};


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 \
{ \
Expand Down
81 changes: 48 additions & 33 deletions native/Avalonia.Native/src/OSX/AvnView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@implementation AvnView
{
ComPtr<TopLevelImpl> _parent;
ComObjectWeakPtr<TopLevelImpl> _parent;
NSTrackingArea* _area;
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed;
AvnInputModifiers _modifierState;
Expand Down Expand Up @@ -132,7 +132,8 @@ -(void)setFrameSize:(NSSize)newSize
_area = nullptr;
}

if (_parent == nullptr)
auto parent = _parent.tryGet();
if (parent == nullptr)
{
return;
}
Expand All @@ -144,7 +145,7 @@ -(void)setFrameSize:(NSSize)newSize
_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];

Expand All @@ -156,26 +157,28 @@ -(void)setFrameSize:(NSSize)newSize

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
Expand All @@ -196,17 +199,19 @@ - (void) viewDidChangeBackingProperties
_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];
}

- (bool) ignoreUserInput:(bool)trigerInputWhenDisabled
{
if(_parent == nullptr)
auto parent = _parent.tryGet();
if(parent == nullptr)
{
return TRUE;
}
Expand All @@ -221,7 +226,7 @@ - (bool) ignoreUserInput:(bool)trigerInputWhenDisabled
{
if(trigerInputWhenDisabled)
{
WindowImpl* windowImpl = dynamic_cast<WindowImpl*>(_parent.getRaw());
auto windowImpl = _parent.tryGetWithCast<WindowImpl>();

if(windowImpl == nullptr){
return FALSE;
Expand Down Expand Up @@ -298,10 +303,10 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
)
)
{
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;
Expand All @@ -313,18 +318,20 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
}
}


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];
}

- (BOOL) resignFirstResponder
{
_parent->TopLevelEvents->LostFocus();
auto parent = _parent.tryGet();
if(parent)
parent->TopLevelEvents->LostFocus();
return YES;
}

Expand Down Expand Up @@ -463,7 +470,8 @@ - (void)mouseExited:(NSEvent *)event

- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
{
if([self ignoreUserInput: false] || _parent == nullptr)
auto parent = _parent.tryGet();
if([self ignoreUserInput: false] || parent == nullptr)
{
return;
}
Expand All @@ -477,7 +485,7 @@ - (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
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
Expand Down Expand Up @@ -551,12 +559,14 @@ - (void)flagsChanged:(NSEvent *)event
}

- (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;
}
Expand All @@ -573,7 +583,7 @@ - (void)keyDown:(NSEvent *)event
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
Expand Down Expand Up @@ -605,7 +615,7 @@ - (void)keyDown:(NSEvent *)event
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]);
}
}
}
Expand Down Expand Up @@ -681,16 +691,18 @@ - (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacemen
}

_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);
Expand Down Expand Up @@ -718,7 +730,8 @@ - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actua

- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
{
if(_parent == nullptr){
auto parent = _parent.tryGet();
if(parent == nullptr){
return;
}

Expand All @@ -737,7 +750,7 @@ - (void)insertText:(id)string replacementRange:(NSRange)replacementRange

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
Expand All @@ -747,7 +760,8 @@ - (NSUInteger)characterIndexForPoint:(NSPoint)point

- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{
if(!_parent->InputMethod->IsActive()){
auto parent = _parent.tryGet();
if(!parent->InputMethod->IsActive()){
return NSZeroRect;
}

Expand All @@ -763,7 +777,8 @@ - (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id <NSDra
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));
Expand Down
Loading

0 comments on commit e2a07cc

Please sign in to comment.