diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm index 00b0d078d7d..5af84019787 100644 --- a/src/corelib/kernel/qcore_mac.mm +++ b/src/corelib/kernel/qcore_mac.mm @@ -774,5 +774,19 @@ QMacVersion::VersionTuple QMacVersion::libraryVersion() // ------------------------------------------------------------------------- +#if !(__has_feature(objc_arc_weak) && __has_feature(objc_arc_fields)) +QT_END_NAMESPACE +@implementation QT_MANGLE_NAMESPACE(WeakPointerLifetimeTracker) +- (void)dealloc +{ + *self.pointer = {}; + [super dealloc]; +} +@end +QT_BEGIN_NAMESPACE +#endif + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index f5ab2327732..30590ef2303 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -462,6 +462,89 @@ qt_objc_cast(id object) // ------------------------------------------------------------------------- +#if defined( __OBJC__) + +template +class QObjCWeakPointer; + +#if __has_feature(objc_arc_weak) && __has_feature(objc_arc_fields) +# define USE_OBJC_WEAK 1 +#endif + +#if !USE_OBJC_WEAK +QT_END_NAMESPACE +#include +Q_CORE_EXPORT +QT_DECLARE_NAMESPACED_OBJC_INTERFACE(WeakPointerLifetimeTracker, NSObject +@property (atomic, assign) QT_PREPEND_NAMESPACE(QObjCWeakPointer) *pointer; +) +QT_BEGIN_NAMESPACE +#endif + +template +class QObjCWeakPointer +{ +public: + QObjCWeakPointer(T *object = nil) : m_object(object) + { +#if !USE_OBJC_WEAK + trackObjectLifetime(); +#endif + } + + QObjCWeakPointer(const QObjCWeakPointer &other) + { + QMacAutoReleasePool pool; + m_object = other.m_object; +#if !USE_OBJC_WEAK + trackObjectLifetime(); +#endif + } + + QObjCWeakPointer &operator=(const QObjCWeakPointer &other) + { + QMacAutoReleasePool pool; + m_object = other.m_object; +#if !USE_OBJC_WEAK + trackObjectLifetime(); +#endif + return *this; + } + + ~QObjCWeakPointer() + { +#if !USE_OBJC_WEAK + if (m_object) + objc_setAssociatedObject(m_object, this, nil, OBJC_ASSOCIATION_RETAIN); +#endif + } + + operator T*() const { return static_cast([[m_object retain] autorelease]); } + +private: +#if USE_OBJC_WEAK + __weak +#else + void trackObjectLifetime() + { + if (!m_object) + return; + + auto *lifetimeTracker = [WeakPointerLifetimeTracker new]; + lifetimeTracker.pointer = reinterpret_cast*>(this); + objc_setAssociatedObject(m_object, this, lifetimeTracker, OBJC_ASSOCIATION_RETAIN); + [lifetimeTracker release]; + } +#endif + NSObject *m_object = nil; +}; + +#undef USE_OBJC_WEAK + +#endif // __OBJC__ + +// ------------------------------------------------------------------------- + QT_END_NAMESPACE #endif // QCORE_MAC_P_H diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h index 30456a91bba..c5c126ecf3e 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.h +++ b/src/plugins/platforms/cocoa/qcocoadrag.h @@ -8,6 +8,8 @@ #include #include +#include + #include #include @@ -36,14 +38,13 @@ public: * event and view when handling an event in QNSView */ void setLastInputEvent(NSEvent *event, NSView *view); - void viewDestroyed(NSView *view); void setAcceptedAction(Qt::DropAction act); void exitDragLoop(); private: QDrag *m_drag; NSEvent *m_lastEvent; - NSView *m_lastView; + QObjCWeakPointer m_lastView; Qt::DropAction m_executed_drop_action; QEventLoop *m_internalDragLoop = nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index bbc75bf6dbe..8e9fd053bda 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -38,17 +38,6 @@ void QCocoaDrag::setLastInputEvent(NSEvent *event, NSView *view) m_lastView = view; } -void QCocoaDrag::viewDestroyed(NSView *view) -{ - if (view == m_lastView) { - if (m_lastEvent.window.contentView == view) { - [m_lastEvent release]; - m_lastEvent = nil; - } - m_lastView = nil; - } -} - QMimeData *QCocoaDrag::dragMimeData() { if (m_drag) @@ -107,8 +96,11 @@ Qt::DropAction QCocoaDrag::defaultAction(Qt::DropActions possibleActions, Qt::DropAction QCocoaDrag::drag(QDrag *o) { m_executed_drop_action = Qt::IgnoreAction; - if (!m_lastEvent) + if (!m_lastView) { + [m_lastEvent release]; + m_lastEvent = nil; return m_executed_drop_action; + } m_drag = o; QMacPasteboard dragBoard(CFStringRef(NSPasteboardNameDrag), QUtiMimeConverter::HandlerScopeFlag::DnD); @@ -151,7 +143,7 @@ bool QCocoaDrag::maybeDragMultipleItems() const QMacAutoReleasePool pool; - NSView *view = m_lastView ? m_lastView : m_lastEvent.window.contentView; + NSView *view = m_lastView ? static_cast(m_lastView) : m_lastEvent.window.contentView; if (![view respondsToSelector:@selector(draggingSession:sourceOperationMaskForDraggingContext:)]) return false; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index e961021d240..560cada5fb4 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -173,10 +173,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper); [[NSNotificationCenter defaultCenter] removeObserver:self]; [m_mouseMoveHelper release]; - // FIXME: Replace with __weak or someting equivalent - QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - nativeDrag->viewDestroyed(self); - [super dealloc]; }